├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── Changelog
├── LICENSE
├── Makefile
├── TODO
├── VERSION
├── compat
└── test-closefrom.c
├── cutils.c
├── cutils.h
├── doc
└── quickjs.texi
├── dtoa.c
├── dtoa.h
├── examples
├── fib.c
├── fib_module.js
├── hello.js
├── hello_module.js
├── message.json
├── pi_bigint.js
├── point.c
├── test_fib.js
└── test_point.js
├── fuzz
├── README
├── fuzz.dict
├── fuzz_common.c
├── fuzz_common.h
├── fuzz_compile.c
├── fuzz_eval.c
├── fuzz_regexp.c
└── generate_dict.js
├── libregexp-opcode.h
├── libregexp.c
├── libregexp.h
├── libunicode-table.h
├── libunicode.c
├── libunicode.h
├── list.h
├── qjs.c
├── qjsc.c
├── quickjs-atom.h
├── quickjs-libc.c
├── quickjs-libc.h
├── quickjs-opcode.h
├── quickjs.c
├── quickjs.h
├── readme-cosmo.txt
├── readme.txt
├── release.sh
├── repl.js
├── run-test262.c
├── test262.conf
├── test262_errors.txt
├── test262o.conf
├── test262o_errors.txt
├── tests
├── assert.js
├── bjson.c
├── fixture_cyclic_import.js
├── microbench.js
├── test262.patch
├── test_bigint.js
├── test_bjson.js
├── test_builtin.js
├── test_closure.js
├── test_cyclic_import.js
├── test_language.js
├── test_loop.js
├── test_std.js
├── test_worker.js
└── test_worker_module.js
├── unicode_download.sh
├── unicode_gen.c
└── unicode_gen_def.h
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: ci
2 |
3 | on:
4 | pull_request:
5 | paths:
6 | - '**'
7 | - '!.gitignore'
8 | - '!LICENSE'
9 | - '!TODO'
10 | - '!doc/**'
11 | - '!examples/**'
12 | - '.github/workflows/ci.yml'
13 | push:
14 | branches:
15 | - '*'
16 |
17 | jobs:
18 | linux:
19 | name: Linux (Ubuntu)
20 | runs-on: ubuntu-latest
21 | strategy:
22 | fail-fast: false
23 | steps:
24 | - uses: actions/checkout@v4
25 | with:
26 | submodules: true
27 | - name: Build
28 | run: |
29 | make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y
30 | - name: Stats
31 | run: |
32 | ./qjs -qd
33 | - name: Run built-in tests
34 | run: |
35 | make test
36 | - name: Run microbench
37 | run: |
38 | make microbench
39 |
40 | linux-lto:
41 | name: Linux LTO
42 | runs-on: ubuntu-latest
43 | strategy:
44 | fail-fast: false
45 | steps:
46 | - uses: actions/checkout@v4
47 | with:
48 | submodules: true
49 | - name: Build
50 | run: |
51 | make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_LTO=y
52 | - name: Run built-in tests
53 | run: |
54 | make test
55 | - name: Run microbench
56 | run: |
57 | make microbench
58 |
59 | linux-32bit:
60 | name: Linux 32bit
61 | runs-on: ubuntu-latest
62 | strategy:
63 | fail-fast: false
64 | steps:
65 | - uses: actions/checkout@v4
66 | with:
67 | submodules: true
68 | - name: Install gcc-multilib
69 | run: |
70 | sudo apt install -y gcc-multilib
71 | - name: Build
72 | run: |
73 | make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_M32=y
74 | - name: Run built-in tests
75 | run: |
76 | make CONFIG_M32=y test
77 |
78 | linux-asan:
79 | runs-on: ubuntu-latest
80 | steps:
81 | - uses: actions/checkout@v4
82 | with:
83 | submodules: true
84 | - name: Build
85 | run: |
86 | make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_ASAN=y
87 | - name: Run built-in tests
88 | env:
89 | ASAN_OPTIONS: halt_on_error=1
90 | run: |
91 | make CONFIG_ASAN=y test
92 |
93 | linux-msan:
94 | runs-on: ubuntu-latest
95 | steps:
96 | - uses: actions/checkout@v4
97 | with:
98 | submodules: true
99 | - name: Build
100 | env:
101 | CC: clang
102 | run: |
103 | make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_MSAN=y CONFIG_CLANG=y
104 | - name: Run built-in tests
105 | env:
106 | MSAN_OPTIONS: halt_on_error=1
107 | run: |
108 | make CONFIG_MSAN=y CONFIG_CLANG=y test
109 |
110 | linux-ubsan:
111 | runs-on: ubuntu-latest
112 | steps:
113 | - uses: actions/checkout@v4
114 | with:
115 | submodules: true
116 | - name: Build
117 | run: |
118 | make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_UBSAN=y
119 | - name: Run built-in tests
120 | env:
121 | UBSAN_OPTIONS: halt_on_error=1
122 | run: |
123 | make CONFIG_UBSAN=y test
124 |
125 | macos:
126 | name: macOS
127 | runs-on: macos-latest
128 | strategy:
129 | fail-fast: false
130 | steps:
131 | - uses: actions/checkout@v4
132 | - name: Build
133 | run: |
134 | make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y
135 | - name: Stats
136 | run: |
137 | ./qjs -qd
138 | - name: Run built-in tests
139 | run: |
140 | make test
141 |
142 | macos-asan:
143 | runs-on: macos-latest
144 | steps:
145 | - uses: actions/checkout@v4
146 | - name: Build
147 | run: |
148 | make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_ASAN=y
149 | - name: Run built-in tests
150 | env:
151 | ASAN_OPTIONS: halt_on_error=1
152 | run: |
153 | make CONFIG_ASAN=y test
154 |
155 | macos-ubsan:
156 | runs-on: macos-latest
157 | steps:
158 | - uses: actions/checkout@v4
159 | - name: Build
160 | run: |
161 | make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_UBSAN=y
162 | - name: Run built-in tests
163 | env:
164 | UBSAN_OPTIONS: halt_on_error=1
165 | run: |
166 | make CONFIG_UBSAN=y test
167 |
168 | freebsd:
169 | runs-on: ubuntu-latest
170 | steps:
171 | - uses: actions/checkout@v4
172 | - name: Build + test
173 | uses: vmactions/freebsd-vm@v1
174 | with:
175 | usesh: true
176 | prepare: |
177 | pkg install -y gmake
178 | run: |
179 | gmake
180 | ./qjs -qd
181 | gmake test
182 |
183 | cosmopolitan:
184 | name: Cosmopolitan
185 | runs-on: ubuntu-latest
186 | strategy:
187 | fail-fast: false
188 | steps:
189 | - uses: actions/checkout@v4
190 | with:
191 | submodules: true
192 | - name: Install Cosmopolitan
193 | run: |
194 | mkdir ~/cosmocc
195 | cd ~/cosmocc
196 | wget https://cosmo.zip/pub/cosmocc/cosmocc.zip
197 | unzip cosmocc.zip
198 | echo "$HOME/cosmocc/bin" >> "$GITHUB_PATH"
199 | - name: Build
200 | run: |
201 | make CONFIG_COSMO=y
202 | - name: Run built-in tests
203 | run: |
204 | make CONFIG_COSMO=y test
205 |
206 | mingw-windows:
207 | name: MinGW Windows target
208 | runs-on: ubuntu-latest
209 | strategy:
210 | fail-fast: false
211 | steps:
212 | - uses: actions/checkout@v4
213 | with:
214 | submodules: true
215 | - name: Install MinGW and Wine
216 | run: |
217 | sudo apt install -y wine mingw-w64
218 | cp /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll .
219 | - name: Setup Wine
220 | run: |
221 | wine --version
222 | winecfg /v
223 | # binfmt doesn't work in GitHub Actions
224 | #sudo apt install -y binfmt-support wine-binfmt
225 | #echo ":Wine:M::MZ::/usr/bin/wine:" > /etc/binfmt.d/wine.conf
226 | #sudo systemctl restart systemd-binfmt
227 | - name: Build
228 | run: |
229 | make CONFIG_WIN32=y
230 | - name: Run built-in tests
231 | run: |
232 | # If binfmt support worked, could just run `make CONFIG_WIN32=y test`
233 | make WINE=/usr/bin/wine CONFIG_WIN32=y test
234 |
235 | windows-msys:
236 | name: Windows MSYS2
237 | runs-on: windows-latest
238 | defaults:
239 | run:
240 | shell: msys2 {0}
241 | steps:
242 | - uses: actions/checkout@v4
243 | - uses: msys2/setup-msys2@v2
244 | with:
245 | msystem: UCRT64
246 | update: true
247 | install: git make mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-dlfcn
248 | - name: Build
249 | run: |
250 | make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y
251 | - name: Stats
252 | run: |
253 | ./qjs -qd
254 | - name: Run built-in tests
255 | run: |
256 | make test
257 | - name: Run microbench
258 | run: |
259 | make microbench
260 |
261 |
262 | qemu-alpine:
263 | runs-on: ubuntu-latest
264 |
265 | strategy:
266 | fail-fast: false
267 | matrix:
268 | platform:
269 | - linux/386
270 | - linux/riscv64
271 | - linux/arm64
272 | - linux/arm/v6
273 | - linux/arm/v7
274 | - linux/s390x
275 | - linux/ppc64le
276 |
277 | steps:
278 | - uses: actions/checkout@v4
279 | with:
280 | submodules: recursive
281 | - name: Get qemu
282 | # See https://github.com/tonistiigi/binfmt/issues/215#issuecomment-2613004741
283 | run: docker run --privileged --rm tonistiigi/binfmt:master --install all
284 | - name: Run tests on ${{ matrix.platform }}
285 | run: docker run --rm --interactive --mount type=bind,source=$(pwd),target=/host --platform ${{ matrix.platform }} alpine sh -c "apk add git patch make gcc libc-dev && cd /host && make test"
286 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.a
2 | .obj/
3 | tests/bjson.so
4 | examples/test_fib
5 | test_fib.c
6 | examples/*.so
7 | examples/hello
8 | examples/hello_module
9 | examples/hello.exe
10 | examples/test_fib.exe
11 | hello.c
12 | microbench*.txt
13 | qjs
14 | qjs.exe
15 | qjsc
16 | qjsc.exe
17 | host-qjsc
18 | qjscalc
19 | qjscalc.c
20 | repl.c
21 | run-test262
22 | run-test262.exe
23 | test262
24 | test262_*.txt
25 | test262o
26 | test262o_*.txt
27 | unicode
28 | unicode_gen
29 | run_octane
30 | run_sunspider_like
31 | libwinpthread*.dll
32 |
--------------------------------------------------------------------------------
/Changelog:
--------------------------------------------------------------------------------
1 | 2025-04-26:
2 |
3 | - removed the bignum extensions and qjscalc
4 | - new BigInt implementation optimized for small numbers
5 | - added WeakRef, FinalizationRegistry and symbols as weakrefs
6 | - added builtin float64 printing and parsing functions for more correctness
7 | - faster repeated string concatenation
8 | - qjs: promise unhandled rejections are fatal errors by default
9 | - added column number in debug information
10 | - removed the "use strip" extension
11 | - qjs: added -s and --strip-source options
12 | - qjsc: added -s and --keep-source options
13 | - added JS_GetAnyOpaque()
14 | - added more callbacks for exotic objects in JSClassExoticMethods
15 | - misc bug fixes
16 |
17 | 2024-01-13:
18 |
19 | - top-level-await support in modules
20 | - allow 'await' in the REPL
21 | - added Array.prototype.{with,toReversed,toSpliced,toSorted} and
22 | TypedArray.prototype.{with,toReversed,toSorted}
23 | - added String.prototype.isWellFormed and String.prototype.toWellFormed
24 | - added Object.groupBy and Map.groupBy
25 | - added Promise.withResolvers
26 | - class static block
27 | - 'in' operator support for private fields
28 | - optional chaining fixes
29 | - added RegExp 'd' flag
30 | - fixed RegExp zero length match logic
31 | - fixed RegExp case insensitive flag
32 | - added os.sleepAsync(), os.getpid() and os.now()
33 | - added cosmopolitan build
34 | - misc bug fixes
35 |
36 | 2023-12-09:
37 |
38 | - added Object.hasOwn, {String|Array|TypedArray}.prototype.at,
39 | {Array|TypedArray}.prototype.findLast{Index}
40 | - BigInt support is enabled even if CONFIG_BIGNUM disabled
41 | - updated to Unicode 15.0.0
42 | - misc bug fixes
43 |
44 | 2021-03-27:
45 |
46 | - faster Array.prototype.push and Array.prototype.unshift
47 | - added JS_UpdateStackTop()
48 | - fixed Windows console
49 | - misc bug fixes
50 |
51 | 2020-11-08:
52 |
53 | - improved function parameter initializers
54 | - added std.setenv(), std.unsetenv() and std.getenviron()
55 | - added JS_EvalThis()
56 | - misc bug fixes
57 |
58 | 2020-09-06:
59 |
60 | - added logical assignment operators
61 | - added IsHTMLDDA support
62 | - faster for-of loops
63 | - os.Worker now takes a module filename as parameter
64 | - qjsc: added -D option to compile dynamically loaded modules or workers
65 | - misc bug fixes
66 |
67 | 2020-07-05:
68 |
69 | - modified JS_GetPrototype() to return a live value
70 | - REPL: support unicode characters larger than 16 bits
71 | - added os.Worker
72 | - improved object serialization
73 | - added std.parseExtJSON
74 | - misc bug fixes
75 |
76 | 2020-04-12:
77 |
78 | - added cross realm support
79 | - added AggregateError and Promise.any
80 | - added env, uid and gid options in os.exec()
81 | - misc bug fixes
82 |
83 | 2020-03-16:
84 |
85 | - reworked error handling in std and os libraries: suppressed I/O
86 | exceptions in std FILE functions and return a positive errno value
87 | when it is explicit
88 | - output exception messages to stderr
89 | - added std.loadFile(), std.strerror(), std.FILE.prototype.tello()
90 | - added JS_GetRuntimeOpaque(), JS_SetRuntimeOpaque(), JS_NewUint32()
91 | - updated to Unicode 13.0.0
92 | - misc bug fixes
93 |
94 | 2020-01-19:
95 |
96 | - keep CONFIG_BIGNUM in the makefile
97 | - added os.chdir()
98 | - qjs: added -I option
99 | - more memory checks in the bignum operations
100 | - modified operator overloading semantics to be closer to the TC39
101 | proposal
102 | - suppressed "use bigint" mode. Simplified "use math" mode
103 | - BigDecimal: changed suffix from 'd' to 'm'
104 | - misc bug fixes
105 |
106 | 2020-01-05:
107 |
108 | - always compile the bignum code. Added '--bignum' option to qjs.
109 | - added BigDecimal
110 | - added String.prototype.replaceAll
111 | - misc bug fixes
112 |
113 | 2019-12-21:
114 |
115 | - added nullish coalescing operator (ES2020)
116 | - added optional chaining (ES2020)
117 | - removed recursions in garbage collector
118 | - test stack overflow in the parser
119 | - improved backtrace logic
120 | - added JS_SetHostPromiseRejectionTracker()
121 | - allow exotic constructors
122 | - improved c++ compatibility
123 | - misc bug fixes
124 |
125 | 2019-10-27:
126 |
127 | - added example of C class in a module (examples/test_point.js)
128 | - added JS_GetTypedArrayBuffer()
129 | - misc bug fixes
130 |
131 | 2019-09-18:
132 |
133 | - added os.exec and other system calls
134 | - exported JS_ValueToAtom()
135 | - qjsc: added 'qjsc_' prefix to the generated C identifiers
136 | - added cross-compilation support
137 | - misc bug fixes
138 |
139 | 2019-09-01:
140 |
141 | - added globalThis
142 | - documented JS_EVAL_FLAG_COMPILE_ONLY
143 | - added import.meta.url and import.meta.main
144 | - added 'debugger' statement
145 | - misc bug fixes
146 |
147 | 2019-08-18:
148 |
149 | - added os.realpath, os.getcwd, os.mkdir, os.stat, os.lstat,
150 | os.readlink, os.readdir, os.utimes, std.popen
151 | - module autodetection
152 | - added import.meta
153 | - misc bug fixes
154 |
155 | 2019-08-10:
156 |
157 | - added public class fields and private class fields, methods and
158 | accessors (TC39 proposal)
159 | - changed JS_ToCStringLen() prototype
160 | - qjsc: handle '-' in module names and modules with the same filename
161 | - added std.urlGet
162 | - exported JS_GetOwnPropertyNames() and JS_GetOwnProperty()
163 | - exported some bigint C functions
164 | - added support for eshost in run-test262
165 | - misc bug fixes
166 |
167 | 2019-07-28:
168 |
169 | - added dynamic import
170 | - added Promise.allSettled
171 | - added String.prototype.matchAll
172 | - added Object.fromEntries
173 | - reduced number of ticks in await
174 | - added BigInt support in Atomics
175 | - exported JS_NewPromiseCapability()
176 | - misc async function and async generator fixes
177 | - enabled hashbang support by default
178 |
179 | 2019-07-21:
180 |
181 | - updated test262 tests
182 | - updated to Unicode version 12.1.0
183 | - fixed missing Date object in qjsc
184 | - fixed multi-context creation
185 | - misc ES2020 related fixes
186 | - simplified power and division operators in bignum extension
187 | - fixed several crash conditions
188 |
189 | 2019-07-09:
190 |
191 | - first public release
192 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | QuickJS Javascript Engine
2 |
3 | Copyright (c) 2017-2021 Fabrice Bellard
4 | Copyright (c) 2017-2021 Charlie Gordon
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # QuickJS Javascript Engine
3 | #
4 | # Copyright (c) 2017-2021 Fabrice Bellard
5 | # Copyright (c) 2017-2021 Charlie Gordon
6 | #
7 | # Permission is hereby granted, free of charge, to any person obtaining a copy
8 | # of this software and associated documentation files (the "Software"), to deal
9 | # in the Software without restriction, including without limitation the rights
10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | # copies of the Software, and to permit persons to whom the Software is
12 | # furnished to do so, subject to the following conditions:
13 | #
14 | # The above copyright notice and this permission notice shall be included in
15 | # all copies or substantial portions of the Software.
16 | #
17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | # THE SOFTWARE.
24 |
25 | ifeq ($(shell uname -s),Darwin)
26 | CONFIG_DARWIN=y
27 | endif
28 | ifeq ($(shell uname -s),FreeBSD)
29 | CONFIG_FREEBSD=y
30 | endif
31 | # Windows cross compilation from Linux
32 | # May need to have libwinpthread*.dll alongside the executable
33 | # (On Ubuntu/Debian may be installed with mingw-w64-x86-64-dev
34 | # to /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll)
35 | #CONFIG_WIN32=y
36 | # use link time optimization (smaller and faster executables but slower build)
37 | #CONFIG_LTO=y
38 | # consider warnings as errors (for development)
39 | #CONFIG_WERROR=y
40 | # force 32 bit build on x86_64
41 | #CONFIG_M32=y
42 | # cosmopolitan build (see https://github.com/jart/cosmopolitan)
43 | #CONFIG_COSMO=y
44 |
45 | # installation directory
46 | PREFIX?=/usr/local
47 |
48 | # use the gprof profiler
49 | #CONFIG_PROFILE=y
50 | # use address sanitizer
51 | #CONFIG_ASAN=y
52 | # use memory sanitizer
53 | #CONFIG_MSAN=y
54 | # use UB sanitizer
55 | #CONFIG_UBSAN=y
56 |
57 | OBJDIR=.obj
58 |
59 | ifdef CONFIG_ASAN
60 | OBJDIR:=$(OBJDIR)/asan
61 | endif
62 | ifdef CONFIG_MSAN
63 | OBJDIR:=$(OBJDIR)/msan
64 | endif
65 | ifdef CONFIG_UBSAN
66 | OBJDIR:=$(OBJDIR)/ubsan
67 | endif
68 |
69 | ifdef CONFIG_DARWIN
70 | # use clang instead of gcc
71 | CONFIG_CLANG=y
72 | CONFIG_DEFAULT_AR=y
73 | endif
74 | ifdef CONFIG_FREEBSD
75 | # use clang instead of gcc
76 | CONFIG_CLANG=y
77 | CONFIG_DEFAULT_AR=y
78 | CONFIG_LTO=
79 | endif
80 |
81 | ifdef CONFIG_WIN32
82 | ifdef CONFIG_M32
83 | CROSS_PREFIX?=i686-w64-mingw32-
84 | else
85 | CROSS_PREFIX?=x86_64-w64-mingw32-
86 | endif
87 | EXE=.exe
88 | else ifdef MSYSTEM
89 | CONFIG_WIN32=y
90 | CROSS_PREFIX?=
91 | EXE=.exe
92 | else
93 | CROSS_PREFIX?=
94 | EXE=
95 | endif
96 |
97 | ifdef CONFIG_CLANG
98 | HOST_CC=clang
99 | CC=$(CROSS_PREFIX)clang
100 | CFLAGS+=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d
101 | CFLAGS += -Wextra
102 | CFLAGS += -Wno-sign-compare
103 | CFLAGS += -Wno-missing-field-initializers
104 | CFLAGS += -Wundef -Wuninitialized
105 | CFLAGS += -Wunused -Wno-unused-parameter
106 | CFLAGS += -Wwrite-strings
107 | CFLAGS += -Wchar-subscripts -funsigned-char
108 | CFLAGS += -MMD -MF $(OBJDIR)/$(@F).d
109 | ifdef CONFIG_DEFAULT_AR
110 | AR=$(CROSS_PREFIX)ar
111 | else
112 | ifdef CONFIG_LTO
113 | AR=$(CROSS_PREFIX)llvm-ar
114 | else
115 | AR=$(CROSS_PREFIX)ar
116 | endif
117 | endif
118 | LIB_FUZZING_ENGINE ?= "-fsanitize=fuzzer"
119 | else ifdef CONFIG_COSMO
120 | CONFIG_LTO=
121 | HOST_CC=gcc
122 | CC=cosmocc
123 | # cosmocc does not correct support -MF
124 | CFLAGS=-g -Wall #-MMD -MF $(OBJDIR)/$(@F).d
125 | CFLAGS += -Wno-array-bounds -Wno-format-truncation
126 | AR=cosmoar
127 | else
128 | HOST_CC=gcc
129 | CC=$(CROSS_PREFIX)gcc
130 | CFLAGS+=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d
131 | CFLAGS += -Wno-array-bounds -Wno-format-truncation -Wno-infinite-recursion
132 | ifdef CONFIG_LTO
133 | AR=$(CROSS_PREFIX)gcc-ar
134 | else
135 | AR=$(CROSS_PREFIX)ar
136 | endif
137 | endif
138 | STRIP?=$(CROSS_PREFIX)strip
139 | ifdef CONFIG_M32
140 | CFLAGS+=-msse2 -mfpmath=sse # use SSE math for correct FP rounding
141 | ifndef CONFIG_WIN32
142 | CFLAGS+=-m32
143 | LDFLAGS+=-m32
144 | endif
145 | endif
146 | CFLAGS+=-fwrapv # ensure that signed overflows behave as expected
147 | ifdef CONFIG_WERROR
148 | CFLAGS+=-Werror
149 | endif
150 | DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\"
151 | ifdef CONFIG_WIN32
152 | DEFINES+=-D__USE_MINGW_ANSI_STDIO # for standard snprintf behavior
153 | endif
154 | ifndef CONFIG_WIN32
155 | ifeq ($(shell $(CC) -o /dev/null compat/test-closefrom.c 2>/dev/null && echo 1),1)
156 | DEFINES+=-DHAVE_CLOSEFROM
157 | endif
158 | endif
159 |
160 | CFLAGS+=$(DEFINES)
161 | CFLAGS_DEBUG=$(CFLAGS) -O0
162 | CFLAGS_SMALL=$(CFLAGS) -Os
163 | CFLAGS_OPT=$(CFLAGS) -O2
164 | CFLAGS_NOLTO:=$(CFLAGS_OPT)
165 | ifdef CONFIG_COSMO
166 | LDFLAGS+=-s # better to strip by default
167 | else
168 | LDFLAGS+=-g
169 | endif
170 | ifdef CONFIG_LTO
171 | CFLAGS_SMALL+=-flto
172 | CFLAGS_OPT+=-flto
173 | LDFLAGS+=-flto
174 | endif
175 | ifdef CONFIG_PROFILE
176 | CFLAGS+=-p
177 | LDFLAGS+=-p
178 | endif
179 | ifdef CONFIG_ASAN
180 | CFLAGS+=-fsanitize=address -fno-omit-frame-pointer
181 | LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer
182 | endif
183 | ifdef CONFIG_MSAN
184 | CFLAGS+=-fsanitize=memory -fno-omit-frame-pointer
185 | LDFLAGS+=-fsanitize=memory -fno-omit-frame-pointer
186 | endif
187 | ifdef CONFIG_UBSAN
188 | CFLAGS+=-fsanitize=undefined -fno-omit-frame-pointer
189 | LDFLAGS+=-fsanitize=undefined -fno-omit-frame-pointer
190 | endif
191 | ifdef CONFIG_WIN32
192 | LDEXPORT=
193 | else
194 | LDEXPORT=-rdynamic
195 | endif
196 |
197 | ifndef CONFIG_COSMO
198 | ifndef CONFIG_DARWIN
199 | ifndef CONFIG_WIN32
200 | CONFIG_SHARED_LIBS=y # building shared libraries is supported
201 | endif
202 | endif
203 | endif
204 |
205 | PROGS=qjs$(EXE) qjsc$(EXE) run-test262$(EXE)
206 |
207 | ifneq ($(CROSS_PREFIX),)
208 | QJSC_CC=gcc
209 | QJSC=./host-qjsc
210 | PROGS+=$(QJSC)
211 | else
212 | QJSC_CC=$(CC)
213 | QJSC=./qjsc$(EXE)
214 | endif
215 | PROGS+=libquickjs.a
216 | ifdef CONFIG_LTO
217 | PROGS+=libquickjs.lto.a
218 | endif
219 |
220 | # examples
221 | ifeq ($(CROSS_PREFIX),)
222 | ifndef CONFIG_ASAN
223 | ifndef CONFIG_MSAN
224 | ifndef CONFIG_UBSAN
225 | PROGS+=examples/hello examples/test_fib
226 | # no -m32 option in qjsc
227 | ifndef CONFIG_M32
228 | ifndef CONFIG_WIN32
229 | PROGS+=examples/hello_module
230 | endif
231 | endif
232 | ifdef CONFIG_SHARED_LIBS
233 | PROGS+=examples/fib.so examples/point.so
234 | endif
235 | endif
236 | endif
237 | endif
238 | endif
239 |
240 | all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS)
241 |
242 | QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/dtoa.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o
243 |
244 | QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS)
245 |
246 | HOST_LIBS=-lm -ldl -lpthread
247 | LIBS=-lm -lpthread
248 | ifndef CONFIG_WIN32
249 | LIBS+=-ldl
250 | endif
251 | LIBS+=$(EXTRA_LIBS)
252 |
253 | $(OBJDIR):
254 | mkdir -p $(OBJDIR) $(OBJDIR)/examples $(OBJDIR)/tests
255 |
256 | qjs$(EXE): $(QJS_OBJS)
257 | $(CC) $(LDFLAGS) $(LDEXPORT) -o $@ $^ $(LIBS)
258 |
259 | qjs-debug$(EXE): $(patsubst %.o, %.debug.o, $(QJS_OBJS))
260 | $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
261 |
262 | qjsc$(EXE): $(OBJDIR)/qjsc.o $(QJS_LIB_OBJS)
263 | $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
264 |
265 | fuzz_eval: $(OBJDIR)/fuzz_eval.o $(OBJDIR)/fuzz_common.o libquickjs.fuzz.a
266 | $(CC) $(CFLAGS_OPT) $^ -o fuzz_eval $(LIB_FUZZING_ENGINE)
267 |
268 | fuzz_compile: $(OBJDIR)/fuzz_compile.o $(OBJDIR)/fuzz_common.o libquickjs.fuzz.a
269 | $(CC) $(CFLAGS_OPT) $^ -o fuzz_compile $(LIB_FUZZING_ENGINE)
270 |
271 | fuzz_regexp: $(OBJDIR)/fuzz_regexp.o $(OBJDIR)/libregexp.fuzz.o $(OBJDIR)/cutils.fuzz.o $(OBJDIR)/libunicode.fuzz.o
272 | $(CC) $(CFLAGS_OPT) $^ -o fuzz_regexp $(LIB_FUZZING_ENGINE)
273 |
274 | libfuzzer: fuzz_eval fuzz_compile fuzz_regexp
275 |
276 | ifneq ($(CROSS_PREFIX),)
277 |
278 | $(QJSC): $(OBJDIR)/qjsc.host.o \
279 | $(patsubst %.o, %.host.o, $(QJS_LIB_OBJS))
280 | $(HOST_CC) $(LDFLAGS) -o $@ $^ $(HOST_LIBS)
281 |
282 | endif #CROSS_PREFIX
283 |
284 | QJSC_DEFINES:=-DCONFIG_CC=\"$(QJSC_CC)\" -DCONFIG_PREFIX=\"$(PREFIX)\"
285 | ifdef CONFIG_LTO
286 | QJSC_DEFINES+=-DCONFIG_LTO
287 | endif
288 | QJSC_HOST_DEFINES:=-DCONFIG_CC=\"$(HOST_CC)\" -DCONFIG_PREFIX=\"$(PREFIX)\"
289 |
290 | $(OBJDIR)/qjsc.o: CFLAGS+=$(QJSC_DEFINES)
291 | $(OBJDIR)/qjsc.host.o: CFLAGS+=$(QJSC_HOST_DEFINES)
292 |
293 | ifdef CONFIG_LTO
294 | LTOEXT=.lto
295 | else
296 | LTOEXT=
297 | endif
298 |
299 | libquickjs$(LTOEXT).a: $(QJS_LIB_OBJS)
300 | $(AR) rcs $@ $^
301 |
302 | ifdef CONFIG_LTO
303 | libquickjs.a: $(patsubst %.o, %.nolto.o, $(QJS_LIB_OBJS))
304 | $(AR) rcs $@ $^
305 | endif # CONFIG_LTO
306 |
307 | libquickjs.fuzz.a: $(patsubst %.o, %.fuzz.o, $(QJS_LIB_OBJS))
308 | $(AR) rcs $@ $^
309 |
310 | repl.c: $(QJSC) repl.js
311 | $(QJSC) -s -c -o $@ -m repl.js
312 |
313 | ifneq ($(wildcard unicode/UnicodeData.txt),)
314 | $(OBJDIR)/libunicode.o $(OBJDIR)/libunicode.nolto.o: libunicode-table.h
315 |
316 | libunicode-table.h: unicode_gen
317 | ./unicode_gen unicode $@
318 | endif
319 |
320 | run-test262$(EXE): $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS)
321 | $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
322 |
323 | run-test262-debug: $(patsubst %.o, %.debug.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS))
324 | $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
325 |
326 | # object suffix order: nolto
327 |
328 | $(OBJDIR)/%.o: %.c | $(OBJDIR)
329 | $(CC) $(CFLAGS_OPT) -c -o $@ $<
330 |
331 | $(OBJDIR)/fuzz_%.o: fuzz/fuzz_%.c | $(OBJDIR)
332 | $(CC) $(CFLAGS_OPT) -c -I. -o $@ $<
333 |
334 | $(OBJDIR)/%.host.o: %.c | $(OBJDIR)
335 | $(HOST_CC) $(CFLAGS_OPT) -c -o $@ $<
336 |
337 | $(OBJDIR)/%.pic.o: %.c | $(OBJDIR)
338 | $(CC) $(CFLAGS_OPT) -fPIC -DJS_SHARED_LIBRARY -c -o $@ $<
339 |
340 | $(OBJDIR)/%.nolto.o: %.c | $(OBJDIR)
341 | $(CC) $(CFLAGS_NOLTO) -c -o $@ $<
342 |
343 | $(OBJDIR)/%.debug.o: %.c | $(OBJDIR)
344 | $(CC) $(CFLAGS_DEBUG) -c -o $@ $<
345 |
346 | $(OBJDIR)/%.fuzz.o: %.c | $(OBJDIR)
347 | $(CC) $(CFLAGS_OPT) -fsanitize=fuzzer-no-link -c -o $@ $<
348 |
349 | $(OBJDIR)/%.check.o: %.c | $(OBJDIR)
350 | $(CC) $(CFLAGS) -DCONFIG_CHECK_JSVALUE -c -o $@ $<
351 |
352 | regexp_test: libregexp.c libunicode.c cutils.c
353 | $(CC) $(LDFLAGS) $(CFLAGS) -DTEST -o $@ libregexp.c libunicode.c cutils.c $(LIBS)
354 |
355 | unicode_gen: $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o libunicode.c unicode_gen_def.h
356 | $(HOST_CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o
357 |
358 | clean:
359 | rm -f repl.c out.c
360 | rm -f *.a *.o *.d *~ unicode_gen regexp_test fuzz_eval fuzz_compile fuzz_regexp $(PROGS)
361 | rm -f hello.c test_fib.c
362 | rm -f examples/*.so tests/*.so
363 | rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug$(EXE)
364 | rm -rf run-test262-debug$(EXE)
365 | rm -f run_octane run_sunspider_like
366 |
367 | install: all
368 | mkdir -p "$(DESTDIR)$(PREFIX)/bin"
369 | $(STRIP) qjs$(EXE) qjsc$(EXE)
370 | install -m755 qjs$(EXE) qjsc$(EXE) "$(DESTDIR)$(PREFIX)/bin"
371 | mkdir -p "$(DESTDIR)$(PREFIX)/lib/quickjs"
372 | install -m644 libquickjs.a "$(DESTDIR)$(PREFIX)/lib/quickjs"
373 | ifdef CONFIG_LTO
374 | install -m644 libquickjs.lto.a "$(DESTDIR)$(PREFIX)/lib/quickjs"
375 | endif
376 | mkdir -p "$(DESTDIR)$(PREFIX)/include/quickjs"
377 | install -m644 quickjs.h quickjs-libc.h "$(DESTDIR)$(PREFIX)/include/quickjs"
378 |
379 | ###############################################################################
380 | # examples
381 |
382 | # example of static JS compilation
383 | HELLO_SRCS=examples/hello.js
384 | HELLO_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \
385 | -fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \
386 | -fno-date -fno-module-loader
387 |
388 | hello.c: $(QJSC) $(HELLO_SRCS)
389 | $(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS)
390 |
391 | examples/hello: $(OBJDIR)/hello.o $(QJS_LIB_OBJS)
392 | $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
393 |
394 | # example of static JS compilation with modules
395 | HELLO_MODULE_SRCS=examples/hello_module.js
396 | HELLO_MODULE_OPTS=-fno-string-normalize -fno-map -fno-typedarray \
397 | -fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \
398 | -fno-date -m
399 | examples/hello_module: $(QJSC) libquickjs$(LTOEXT).a $(HELLO_MODULE_SRCS)
400 | $(QJSC) $(HELLO_MODULE_OPTS) -o $@ $(HELLO_MODULE_SRCS)
401 |
402 | # use of an external C module (static compilation)
403 |
404 | test_fib.c: $(QJSC) examples/test_fib.js
405 | $(QJSC) -e -M examples/fib.so,fib -m -o $@ examples/test_fib.js
406 |
407 | examples/test_fib: $(OBJDIR)/test_fib.o $(OBJDIR)/examples/fib.o libquickjs$(LTOEXT).a
408 | $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
409 |
410 | examples/fib.so: $(OBJDIR)/examples/fib.pic.o
411 | $(CC) $(LDFLAGS) -shared -o $@ $^
412 |
413 | examples/point.so: $(OBJDIR)/examples/point.pic.o
414 | $(CC) $(LDFLAGS) -shared -o $@ $^
415 |
416 | ###############################################################################
417 | # documentation
418 |
419 | DOCS=doc/quickjs.pdf doc/quickjs.html
420 |
421 | build_doc: $(DOCS)
422 |
423 | clean_doc:
424 | rm -f $(DOCS)
425 |
426 | doc/version.texi: VERSION
427 | @echo "@set VERSION `cat $<`" > $@
428 |
429 | doc/%.pdf: doc/%.texi doc/version.texi
430 | texi2pdf --clean -o $@ -q $<
431 |
432 | doc/%.html.pre: doc/%.texi doc/version.texi
433 | makeinfo --html --no-headers --no-split --number-sections -o $@ $<
434 |
435 | doc/%.html: doc/%.html.pre
436 | sed -e 's||\n|' < $< > $@
437 |
438 | ###############################################################################
439 | # tests
440 |
441 | ifdef CONFIG_SHARED_LIBS
442 | test: tests/bjson.so examples/point.so
443 | endif
444 |
445 | test: qjs$(EXE)
446 | $(WINE) ./qjs$(EXE) tests/test_closure.js
447 | $(WINE) ./qjs$(EXE) tests/test_language.js
448 | $(WINE) ./qjs$(EXE) --std tests/test_builtin.js
449 | $(WINE) ./qjs$(EXE) tests/test_loop.js
450 | $(WINE) ./qjs$(EXE) tests/test_bigint.js
451 | $(WINE) ./qjs$(EXE) tests/test_cyclic_import.js
452 | $(WINE) ./qjs$(EXE) tests/test_worker.js
453 | ifndef CONFIG_WIN32
454 | $(WINE) ./qjs$(EXE) tests/test_std.js
455 | endif
456 | ifdef CONFIG_SHARED_LIBS
457 | $(WINE) ./qjs$(EXE) tests/test_bjson.js
458 | $(WINE) ./qjs$(EXE) examples/test_point.js
459 | endif
460 |
461 | stats: qjs$(EXE)
462 | $(WINE) ./qjs$(EXE) -qd
463 |
464 | microbench: qjs$(EXE)
465 | $(WINE) ./qjs$(EXE) --std tests/microbench.js
466 |
467 | ifeq ($(wildcard test262o/tests.txt),)
468 | test2o test2o-update:
469 | @echo test262o tests not installed
470 | else
471 | # ES5 tests (obsolete)
472 | test2o: run-test262
473 | time ./run-test262 -t -m -c test262o.conf
474 |
475 | test2o-update: run-test262
476 | ./run-test262 -t -u -c test262o.conf
477 | endif
478 |
479 | ifeq ($(wildcard test262/features.txt),)
480 | test2 test2-update test2-default test2-check:
481 | @echo test262 tests not installed
482 | else
483 | # Test262 tests
484 | test2-default: run-test262
485 | time ./run-test262 -t -m -c test262.conf
486 |
487 | test2: run-test262
488 | time ./run-test262 -t -m -c test262.conf -a
489 |
490 | test2-update: run-test262
491 | ./run-test262 -t -u -c test262.conf -a
492 |
493 | test2-check: run-test262
494 | time ./run-test262 -t -m -c test262.conf -E -a
495 | endif
496 |
497 | testall: all test microbench test2o test2
498 |
499 | testall-complete: testall
500 |
501 | node-test:
502 | node tests/test_closure.js
503 | node tests/test_language.js
504 | node tests/test_builtin.js
505 | node tests/test_loop.js
506 | node tests/test_bigint.js
507 |
508 | node-microbench:
509 | node tests/microbench.js -s microbench-node.txt
510 | node --jitless tests/microbench.js -s microbench-node-jitless.txt
511 |
512 | bench-v8: qjs
513 | make -C tests/bench-v8
514 | ./qjs -d tests/bench-v8/combined.js
515 |
516 | node-bench-v8:
517 | make -C tests/bench-v8
518 | node --jitless tests/bench-v8/combined.js
519 |
520 | tests/bjson.so: $(OBJDIR)/tests/bjson.pic.o
521 | $(CC) $(LDFLAGS) -shared -o $@ $^ $(LIBS)
522 |
523 | BENCHMARKDIR=../quickjs-benchmarks
524 |
525 | run_sunspider_like: $(BENCHMARKDIR)/run_sunspider_like.c
526 | $(CC) $(CFLAGS) $(LDFLAGS) -DNO_INCLUDE_DIR -I. -o $@ $< libquickjs$(LTOEXT).a $(LIBS)
527 |
528 | run_octane: $(BENCHMARKDIR)/run_octane.c
529 | $(CC) $(CFLAGS) $(LDFLAGS) -DNO_INCLUDE_DIR -I. -o $@ $< libquickjs$(LTOEXT).a $(LIBS)
530 |
531 | benchmarks: run_sunspider_like run_octane
532 | ./run_sunspider_like $(BENCHMARKDIR)/kraken-1.0/
533 | ./run_sunspider_like $(BENCHMARKDIR)/kraken-1.1/
534 | ./run_sunspider_like $(BENCHMARKDIR)/sunspider-1.0/
535 | ./run_octane $(BENCHMARKDIR)/
536 |
537 | -include $(wildcard $(OBJDIR)/*.d)
538 |
--------------------------------------------------------------------------------
/TODO:
--------------------------------------------------------------------------------
1 | Misc ideas:
2 | - use custom printf to avoid compatibility issues with floating point numbers
3 | - consistent naming for preprocessor defines
4 | - unify coding style and naming conventions
5 | - use names from the ECMA spec in library implementation
6 | - use byte code emitters with typed arguments (for clarity)
7 | - use 2 bytecode DynBufs in JSFunctionDef, one for reading, one for writing
8 | and use the same wrappers in all phases
9 | - use more generic method for line numbers in resolve_variables and resolve_labels
10 | - use custom timezone support to avoid C library compatibility issues
11 |
12 | Memory:
13 | - use memory pools for objects, etc?
14 | - test border cases for max number of atoms, object properties, string length
15 | - add emergency malloc mode for out of memory exceptions.
16 | - test all DynBuf memory errors
17 | - test all js_realloc memory errors
18 | - improve JS_ComputeMemoryUsage() with more info
19 |
20 | Built-in standard library:
21 | - BSD sockets
22 | - modules: use realpath in module name normalizer and put it in quickjs-libc
23 | - modules: if no ".", use a well known module loading path ?
24 | - get rid of __loadScript, use more common name
25 |
26 | REPL:
27 | - debugger
28 | - readline: support MS Windows terminal
29 | - readline: handle dynamic terminal resizing
30 | - readline: handle double width unicode characters
31 | - multiline editing
32 | - runtime object and function inspectors
33 | - interactive object browser
34 | - use more generic approach to display evaluation results
35 | - improve directive handling: dispatch, colorize, completion...
36 | - save history
37 | - close all predefined methods in repl.js and jscalc.js
38 |
39 | Optimization ideas:
40 | - use 64 bit JSValue in 64 bit mode
41 | - use JSValue as atoms and use a specific constant pool in functions to
42 | reference atoms from the bytecode
43 | - reuse stack slots for disjoint scopes, if strip
44 | - add heuristic to avoid some cycles in closures
45 | - small String (1 codepoint) with immediate storage
46 | - perform static string concatenation at compile time
47 | - add implicit numeric strings for Uint32 numbers?
48 | - optimize `s += a + b`, `s += a.b` and similar simple expressions
49 | - ensure string canonical representation and optimise comparisons and hashes?
50 | - property access optimization on the global object, functions,
51 | prototypes and special non extensible objects.
52 | - create object literals with the correct length by backpatching length argument
53 | - remove redundant set_loc_uninitialized/check_uninitialized opcodes
54 | - peephole optim: push_atom_value, to_propkey -> push_atom_value
55 | - peephole optim: put_loc x, get_loc_check x -> set_loc x
56 | - convert slow array to fast array when all properties != length are numeric
57 | - optimize destructuring assignments for global and local variables
58 | - implement some form of tail-call-optimization
59 | - optimize OP_apply
60 | - optimize f(...b)
61 |
62 | Test262o: 0/11262 errors, 463 excluded
63 | Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
64 |
65 | Result: 47/79321 errors, 1617 excluded, 6767 skipped
66 | Test262 commit: 4b5d36ab6ef2f59d0a8902cd383762547a3a74c4
67 |
--------------------------------------------------------------------------------
/VERSION:
--------------------------------------------------------------------------------
1 | 2025-04-26
2 |
--------------------------------------------------------------------------------
/compat/test-closefrom.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main(void) {
4 | closefrom(3);
5 | return 0;
6 | }
7 |
--------------------------------------------------------------------------------
/cutils.h:
--------------------------------------------------------------------------------
1 | /*
2 | * C utilities
3 | *
4 | * Copyright (c) 2017 Fabrice Bellard
5 | * Copyright (c) 2018 Charlie Gordon
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | */
25 | #ifndef CUTILS_H
26 | #define CUTILS_H
27 |
28 | #include
29 | #include
30 | #include
31 |
32 | #define likely(x) __builtin_expect(!!(x), 1)
33 | #define unlikely(x) __builtin_expect(!!(x), 0)
34 | #define force_inline inline __attribute__((always_inline))
35 | #define no_inline __attribute__((noinline))
36 | #define __maybe_unused __attribute__((unused))
37 |
38 | #define xglue(x, y) x ## y
39 | #define glue(x, y) xglue(x, y)
40 | #define stringify(s) tostring(s)
41 | #define tostring(s) #s
42 |
43 | #ifndef offsetof
44 | #define offsetof(type, field) ((size_t) &((type *)0)->field)
45 | #endif
46 | #ifndef countof
47 | #define countof(x) (sizeof(x) / sizeof((x)[0]))
48 | #endif
49 | #ifndef container_of
50 | /* return the pointer of type 'type *' containing 'ptr' as field 'member' */
51 | #define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member)))
52 | #endif
53 |
54 | #if !defined(_MSC_VER) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
55 | #define minimum_length(n) static n
56 | #else
57 | #define minimum_length(n) n
58 | #endif
59 |
60 | typedef int BOOL;
61 |
62 | #ifndef FALSE
63 | enum {
64 | FALSE = 0,
65 | TRUE = 1,
66 | };
67 | #endif
68 |
69 | void pstrcpy(char *buf, int buf_size, const char *str);
70 | char *pstrcat(char *buf, int buf_size, const char *s);
71 | int strstart(const char *str, const char *val, const char **ptr);
72 | int has_suffix(const char *str, const char *suffix);
73 |
74 | /* Prevent UB when n == 0 and (src == NULL or dest == NULL) */
75 | static inline void memcpy_no_ub(void *dest, const void *src, size_t n) {
76 | if (n)
77 | memcpy(dest, src, n);
78 | }
79 |
80 | static inline int max_int(int a, int b)
81 | {
82 | if (a > b)
83 | return a;
84 | else
85 | return b;
86 | }
87 |
88 | static inline int min_int(int a, int b)
89 | {
90 | if (a < b)
91 | return a;
92 | else
93 | return b;
94 | }
95 |
96 | static inline uint32_t max_uint32(uint32_t a, uint32_t b)
97 | {
98 | if (a > b)
99 | return a;
100 | else
101 | return b;
102 | }
103 |
104 | static inline uint32_t min_uint32(uint32_t a, uint32_t b)
105 | {
106 | if (a < b)
107 | return a;
108 | else
109 | return b;
110 | }
111 |
112 | static inline int64_t max_int64(int64_t a, int64_t b)
113 | {
114 | if (a > b)
115 | return a;
116 | else
117 | return b;
118 | }
119 |
120 | static inline int64_t min_int64(int64_t a, int64_t b)
121 | {
122 | if (a < b)
123 | return a;
124 | else
125 | return b;
126 | }
127 |
128 | /* WARNING: undefined if a = 0 */
129 | static inline int clz32(unsigned int a)
130 | {
131 | return __builtin_clz(a);
132 | }
133 |
134 | /* WARNING: undefined if a = 0 */
135 | static inline int clz64(uint64_t a)
136 | {
137 | return __builtin_clzll(a);
138 | }
139 |
140 | /* WARNING: undefined if a = 0 */
141 | static inline int ctz32(unsigned int a)
142 | {
143 | return __builtin_ctz(a);
144 | }
145 |
146 | /* WARNING: undefined if a = 0 */
147 | static inline int ctz64(uint64_t a)
148 | {
149 | return __builtin_ctzll(a);
150 | }
151 |
152 | struct __attribute__((packed)) packed_u64 {
153 | uint64_t v;
154 | };
155 |
156 | struct __attribute__((packed)) packed_u32 {
157 | uint32_t v;
158 | };
159 |
160 | struct __attribute__((packed)) packed_u16 {
161 | uint16_t v;
162 | };
163 |
164 | static inline uint64_t get_u64(const uint8_t *tab)
165 | {
166 | return ((const struct packed_u64 *)tab)->v;
167 | }
168 |
169 | static inline int64_t get_i64(const uint8_t *tab)
170 | {
171 | return (int64_t)((const struct packed_u64 *)tab)->v;
172 | }
173 |
174 | static inline void put_u64(uint8_t *tab, uint64_t val)
175 | {
176 | ((struct packed_u64 *)tab)->v = val;
177 | }
178 |
179 | static inline uint32_t get_u32(const uint8_t *tab)
180 | {
181 | return ((const struct packed_u32 *)tab)->v;
182 | }
183 |
184 | static inline int32_t get_i32(const uint8_t *tab)
185 | {
186 | return (int32_t)((const struct packed_u32 *)tab)->v;
187 | }
188 |
189 | static inline void put_u32(uint8_t *tab, uint32_t val)
190 | {
191 | ((struct packed_u32 *)tab)->v = val;
192 | }
193 |
194 | static inline uint32_t get_u16(const uint8_t *tab)
195 | {
196 | return ((const struct packed_u16 *)tab)->v;
197 | }
198 |
199 | static inline int32_t get_i16(const uint8_t *tab)
200 | {
201 | return (int16_t)((const struct packed_u16 *)tab)->v;
202 | }
203 |
204 | static inline void put_u16(uint8_t *tab, uint16_t val)
205 | {
206 | ((struct packed_u16 *)tab)->v = val;
207 | }
208 |
209 | static inline uint32_t get_u8(const uint8_t *tab)
210 | {
211 | return *tab;
212 | }
213 |
214 | static inline int32_t get_i8(const uint8_t *tab)
215 | {
216 | return (int8_t)*tab;
217 | }
218 |
219 | static inline void put_u8(uint8_t *tab, uint8_t val)
220 | {
221 | *tab = val;
222 | }
223 |
224 | #ifndef bswap16
225 | static inline uint16_t bswap16(uint16_t x)
226 | {
227 | return (x >> 8) | (x << 8);
228 | }
229 | #endif
230 |
231 | #ifndef bswap32
232 | static inline uint32_t bswap32(uint32_t v)
233 | {
234 | return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) |
235 | ((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24);
236 | }
237 | #endif
238 |
239 | #ifndef bswap64
240 | static inline uint64_t bswap64(uint64_t v)
241 | {
242 | return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) |
243 | ((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) |
244 | ((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) |
245 | ((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) |
246 | ((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) |
247 | ((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) |
248 | ((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) |
249 | ((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8));
250 | }
251 | #endif
252 |
253 | /* XXX: should take an extra argument to pass slack information to the caller */
254 | typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size);
255 |
256 | typedef struct DynBuf {
257 | uint8_t *buf;
258 | size_t size;
259 | size_t allocated_size;
260 | BOOL error; /* true if a memory allocation error occurred */
261 | DynBufReallocFunc *realloc_func;
262 | void *opaque; /* for realloc_func */
263 | } DynBuf;
264 |
265 | void dbuf_init(DynBuf *s);
266 | void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func);
267 | int dbuf_realloc(DynBuf *s, size_t new_size);
268 | int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len);
269 | int dbuf_put(DynBuf *s, const uint8_t *data, size_t len);
270 | int dbuf_put_self(DynBuf *s, size_t offset, size_t len);
271 | int dbuf_putc(DynBuf *s, uint8_t c);
272 | int dbuf_putstr(DynBuf *s, const char *str);
273 | static inline int dbuf_put_u16(DynBuf *s, uint16_t val)
274 | {
275 | return dbuf_put(s, (uint8_t *)&val, 2);
276 | }
277 | static inline int dbuf_put_u32(DynBuf *s, uint32_t val)
278 | {
279 | return dbuf_put(s, (uint8_t *)&val, 4);
280 | }
281 | static inline int dbuf_put_u64(DynBuf *s, uint64_t val)
282 | {
283 | return dbuf_put(s, (uint8_t *)&val, 8);
284 | }
285 | int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
286 | const char *fmt, ...);
287 | void dbuf_free(DynBuf *s);
288 | static inline BOOL dbuf_error(DynBuf *s) {
289 | return s->error;
290 | }
291 | static inline void dbuf_set_error(DynBuf *s)
292 | {
293 | s->error = TRUE;
294 | }
295 |
296 | #define UTF8_CHAR_LEN_MAX 6
297 |
298 | int unicode_to_utf8(uint8_t *buf, unsigned int c);
299 | int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp);
300 |
301 | static inline BOOL is_surrogate(uint32_t c)
302 | {
303 | return (c >> 11) == (0xD800 >> 11); // 0xD800-0xDFFF
304 | }
305 |
306 | static inline BOOL is_hi_surrogate(uint32_t c)
307 | {
308 | return (c >> 10) == (0xD800 >> 10); // 0xD800-0xDBFF
309 | }
310 |
311 | static inline BOOL is_lo_surrogate(uint32_t c)
312 | {
313 | return (c >> 10) == (0xDC00 >> 10); // 0xDC00-0xDFFF
314 | }
315 |
316 | static inline uint32_t get_hi_surrogate(uint32_t c)
317 | {
318 | return (c >> 10) - (0x10000 >> 10) + 0xD800;
319 | }
320 |
321 | static inline uint32_t get_lo_surrogate(uint32_t c)
322 | {
323 | return (c & 0x3FF) | 0xDC00;
324 | }
325 |
326 | static inline uint32_t from_surrogate(uint32_t hi, uint32_t lo)
327 | {
328 | return 0x10000 + 0x400 * (hi - 0xD800) + (lo - 0xDC00);
329 | }
330 |
331 | static inline int from_hex(int c)
332 | {
333 | if (c >= '0' && c <= '9')
334 | return c - '0';
335 | else if (c >= 'A' && c <= 'F')
336 | return c - 'A' + 10;
337 | else if (c >= 'a' && c <= 'f')
338 | return c - 'a' + 10;
339 | else
340 | return -1;
341 | }
342 |
343 | void rqsort(void *base, size_t nmemb, size_t size,
344 | int (*cmp)(const void *, const void *, void *),
345 | void *arg);
346 |
347 | static inline uint64_t float64_as_uint64(double d)
348 | {
349 | union {
350 | double d;
351 | uint64_t u64;
352 | } u;
353 | u.d = d;
354 | return u.u64;
355 | }
356 |
357 | static inline double uint64_as_float64(uint64_t u64)
358 | {
359 | union {
360 | double d;
361 | uint64_t u64;
362 | } u;
363 | u.u64 = u64;
364 | return u.d;
365 | }
366 |
367 | static inline double fromfp16(uint16_t v)
368 | {
369 | double d;
370 | uint32_t v1;
371 | v1 = v & 0x7fff;
372 | if (unlikely(v1 >= 0x7c00))
373 | v1 += 0x1f8000; /* NaN or infinity */
374 | d = uint64_as_float64(((uint64_t)(v >> 15) << 63) | ((uint64_t)v1 << (52 - 10)));
375 | return d * 0x1p1008;
376 | }
377 |
378 | static inline uint16_t tofp16(double d)
379 | {
380 | uint64_t a, addend;
381 | uint32_t v, sgn;
382 | int shift;
383 |
384 | a = float64_as_uint64(d);
385 | sgn = a >> 63;
386 | a = a & 0x7fffffffffffffff;
387 | if (unlikely(a > 0x7ff0000000000000)) {
388 | /* nan */
389 | v = 0x7c01;
390 | } else if (a < 0x3f10000000000000) { /* 0x1p-14 */
391 | /* subnormal f16 number or zero */
392 | if (a <= 0x3e60000000000000) { /* 0x1p-25 */
393 | v = 0x0000; /* zero */
394 | } else {
395 | shift = 1051 - (a >> 52);
396 | a = ((uint64_t)1 << 52) | (a & (((uint64_t)1 << 52) - 1));
397 | addend = ((a >> shift) & 1) + (((uint64_t)1 << (shift - 1)) - 1);
398 | v = (a + addend) >> shift;
399 | }
400 | } else {
401 | /* normal number or infinity */
402 | a -= 0x3f00000000000000; /* adjust the exponent */
403 | /* round */
404 | addend = ((a >> (52 - 10)) & 1) + (((uint64_t)1 << (52 - 11)) - 1);
405 | v = (a + addend) >> (52 - 10);
406 | /* overflow ? */
407 | if (unlikely(v > 0x7c00))
408 | v = 0x7c00;
409 | }
410 | return v | (sgn << 15);
411 | }
412 |
413 | static inline int isfp16nan(uint16_t v)
414 | {
415 | return (v & 0x7FFF) > 0x7C00;
416 | }
417 |
418 | static inline int isfp16zero(uint16_t v)
419 | {
420 | return (v & 0x7FFF) == 0;
421 | }
422 |
423 | #endif /* CUTILS_H */
424 |
--------------------------------------------------------------------------------
/dtoa.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Tiny float64 printing and parsing library
3 | *
4 | * Copyright (c) 2024 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | //#define JS_DTOA_DUMP_STATS
26 |
27 | /* maximum number of digits for fixed and frac formats */
28 | #define JS_DTOA_MAX_DIGITS 101
29 |
30 | /* radix != 10 is only supported with flags = JS_DTOA_FORMAT_FREE */
31 | /* use as many digits as necessary */
32 | #define JS_DTOA_FORMAT_FREE (0 << 0)
33 | /* use n_digits significant digits (1 <= n_digits <= JS_DTOA_MAX_DIGITS) */
34 | #define JS_DTOA_FORMAT_FIXED (1 << 0)
35 | /* force fractional format: [-]dd.dd with n_digits fractional digits.
36 | 0 <= n_digits <= JS_DTOA_MAX_DIGITS */
37 | #define JS_DTOA_FORMAT_FRAC (2 << 0)
38 | #define JS_DTOA_FORMAT_MASK (3 << 0)
39 |
40 | /* select exponential notation either in fixed or free format */
41 | #define JS_DTOA_EXP_AUTO (0 << 2)
42 | #define JS_DTOA_EXP_ENABLED (1 << 2)
43 | #define JS_DTOA_EXP_DISABLED (2 << 2)
44 | #define JS_DTOA_EXP_MASK (3 << 2)
45 |
46 | #define JS_DTOA_MINUS_ZERO (1 << 4) /* show the minus sign for -0 */
47 |
48 | /* only accepts integers (no dot, no exponent) */
49 | #define JS_ATOD_INT_ONLY (1 << 0)
50 | /* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */
51 | #define JS_ATOD_ACCEPT_BIN_OCT (1 << 1)
52 | /* accept O prefix as octal if radix == 0 and properly formed (Annex B) */
53 | #define JS_ATOD_ACCEPT_LEGACY_OCTAL (1 << 2)
54 | /* accept _ between digits as a digit separator */
55 | #define JS_ATOD_ACCEPT_UNDERSCORES (1 << 3)
56 |
57 | typedef struct {
58 | uint64_t mem[37];
59 | } JSDTOATempMem;
60 |
61 | typedef struct {
62 | uint64_t mem[27];
63 | } JSATODTempMem;
64 |
65 | /* return a maximum bound of the string length */
66 | int js_dtoa_max_len(double d, int radix, int n_digits, int flags);
67 | /* return the string length */
68 | int js_dtoa(char *buf, double d, int radix, int n_digits, int flags,
69 | JSDTOATempMem *tmp_mem);
70 | double js_atod(const char *str, const char **pnext, int radix, int flags,
71 | JSATODTempMem *tmp_mem);
72 |
73 | #ifdef JS_DTOA_DUMP_STATS
74 | void js_dtoa_dump_stats(void);
75 | #endif
76 |
77 | /* additional exported functions */
78 | size_t u32toa(char *buf, uint32_t n);
79 | size_t i32toa(char *buf, int32_t n);
80 | size_t u64toa(char *buf, uint64_t n);
81 | size_t i64toa(char *buf, int64_t n);
82 | size_t u64toa_radix(char *buf, uint64_t n, unsigned int radix);
83 | size_t i64toa_radix(char *buf, int64_t n, unsigned int radix);
84 |
--------------------------------------------------------------------------------
/examples/fib.c:
--------------------------------------------------------------------------------
1 | /*
2 | * QuickJS: Example of C module
3 | *
4 | * Copyright (c) 2017-2018 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | #include "../quickjs.h"
25 |
26 | #define countof(x) (sizeof(x) / sizeof((x)[0]))
27 |
28 | static int fib(int n)
29 | {
30 | if (n <= 0)
31 | return 0;
32 | else if (n == 1)
33 | return 1;
34 | else
35 | return fib(n - 1) + fib(n - 2);
36 | }
37 |
38 | static JSValue js_fib(JSContext *ctx, JSValueConst this_val,
39 | int argc, JSValueConst *argv)
40 | {
41 | int n, res;
42 | if (JS_ToInt32(ctx, &n, argv[0]))
43 | return JS_EXCEPTION;
44 | res = fib(n);
45 | return JS_NewInt32(ctx, res);
46 | }
47 |
48 | static const JSCFunctionListEntry js_fib_funcs[] = {
49 | JS_CFUNC_DEF("fib", 1, js_fib ),
50 | };
51 |
52 | static int js_fib_init(JSContext *ctx, JSModuleDef *m)
53 | {
54 | return JS_SetModuleExportList(ctx, m, js_fib_funcs,
55 | countof(js_fib_funcs));
56 | }
57 |
58 | #ifdef JS_SHARED_LIBRARY
59 | #define JS_INIT_MODULE js_init_module
60 | #else
61 | #define JS_INIT_MODULE js_init_module_fib
62 | #endif
63 |
64 | JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)
65 | {
66 | JSModuleDef *m;
67 | m = JS_NewCModule(ctx, module_name, js_fib_init);
68 | if (!m)
69 | return NULL;
70 | JS_AddModuleExportList(ctx, m, js_fib_funcs, countof(js_fib_funcs));
71 | return m;
72 | }
73 |
--------------------------------------------------------------------------------
/examples/fib_module.js:
--------------------------------------------------------------------------------
1 | /* fib module */
2 | export function fib(n)
3 | {
4 | if (n <= 0)
5 | return 0;
6 | else if (n == 1)
7 | return 1;
8 | else
9 | return fib(n - 1) + fib(n - 2);
10 | }
11 |
--------------------------------------------------------------------------------
/examples/hello.js:
--------------------------------------------------------------------------------
1 | console.log("Hello World");
2 |
--------------------------------------------------------------------------------
/examples/hello_module.js:
--------------------------------------------------------------------------------
1 | /* example of JS and JSON modules */
2 |
3 | import { fib } from "./fib_module.js";
4 | import msg from "./message.json";
5 |
6 | console.log("Hello World");
7 | console.log("fib(10)=", fib(10));
8 | console.log("msg=", msg);
9 |
--------------------------------------------------------------------------------
/examples/message.json:
--------------------------------------------------------------------------------
1 | { "x" : 1, "tab": [ 1, 2, 3 ] }
2 |
3 |
--------------------------------------------------------------------------------
/examples/pi_bigint.js:
--------------------------------------------------------------------------------
1 | /*
2 | * PI computation in Javascript using the BigInt type
3 | */
4 | "use strict";
5 |
6 | /* return floor(log2(a)) for a > 0 and 0 for a = 0 */
7 | function floor_log2(a)
8 | {
9 | var k_max, a1, k, i;
10 | k_max = 0n;
11 | while ((a >> (2n ** k_max)) != 0n) {
12 | k_max++;
13 | }
14 | k = 0n;
15 | a1 = a;
16 | for(i = k_max - 1n; i >= 0n; i--) {
17 | a1 = a >> (2n ** i);
18 | if (a1 != 0n) {
19 | a = a1;
20 | k |= (1n << i);
21 | }
22 | }
23 | return k;
24 | }
25 |
26 | /* return ceil(log2(a)) for a > 0 */
27 | function ceil_log2(a)
28 | {
29 | return floor_log2(a - 1n) + 1n;
30 | }
31 |
32 | /* return floor(sqrt(a)) (not efficient but simple) */
33 | function int_sqrt(a)
34 | {
35 | var l, u, s;
36 | if (a == 0n)
37 | return a;
38 | l = ceil_log2(a);
39 | u = 1n << ((l + 1n) / 2n);
40 | /* u >= floor(sqrt(a)) */
41 | for(;;) {
42 | s = u;
43 | u = ((a / s) + s) / 2n;
44 | if (u >= s)
45 | break;
46 | }
47 | return s;
48 | }
49 |
50 | /* return pi * 2**prec */
51 | function calc_pi(prec) {
52 | const CHUD_A = 13591409n;
53 | const CHUD_B = 545140134n;
54 | const CHUD_C = 640320n;
55 | const CHUD_C3 = 10939058860032000n; /* C^3/24 */
56 | const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */
57 |
58 | /* return [P, Q, G] */
59 | function chud_bs(a, b, need_G) {
60 | var c, P, Q, G, P1, Q1, G1, P2, Q2, G2;
61 | if (a == (b - 1n)) {
62 | G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n);
63 | P = G * (CHUD_B * b + CHUD_A);
64 | if (b & 1n)
65 | P = -P;
66 | Q = b * b * b * CHUD_C3;
67 | } else {
68 | c = (a + b) >> 1n;
69 | [P1, Q1, G1] = chud_bs(a, c, true);
70 | [P2, Q2, G2] = chud_bs(c, b, need_G);
71 | P = P1 * Q2 + P2 * G1;
72 | Q = Q1 * Q2;
73 | if (need_G)
74 | G = G1 * G2;
75 | else
76 | G = 0n;
77 | }
78 | return [P, Q, G];
79 | }
80 |
81 | var n, P, Q, G;
82 | /* number of serie terms */
83 | n = BigInt(Math.ceil(Number(prec) / CHUD_BITS_PER_TERM)) + 10n;
84 | [P, Q, G] = chud_bs(0n, n, false);
85 | Q = (CHUD_C / 12n) * (Q << prec) / (P + Q * CHUD_A);
86 | G = int_sqrt(CHUD_C << (2n * prec));
87 | return (Q * G) >> prec;
88 | }
89 |
90 | function main(args) {
91 | var r, n_digits, n_bits, out;
92 | if (args.length < 1) {
93 | print("usage: pi n_digits");
94 | return;
95 | }
96 | n_digits = args[0] | 0;
97 |
98 | /* we add more bits to reduce the probability of bad rounding for
99 | the last digits */
100 | n_bits = BigInt(Math.ceil(n_digits * Math.log2(10))) + 32n;
101 | r = calc_pi(n_bits);
102 | r = ((10n ** BigInt(n_digits)) * r) >> n_bits;
103 | out = r.toString();
104 | print(out[0] + "." + out.slice(1));
105 | }
106 |
107 | var args;
108 | if (typeof scriptArgs != "undefined") {
109 | args = scriptArgs;
110 | args.shift();
111 | } else if (typeof arguments != "undefined") {
112 | args = arguments;
113 | } else {
114 | /* default: 1000 digits */
115 | args=[1000];
116 | }
117 |
118 | main(args);
119 |
--------------------------------------------------------------------------------
/examples/point.c:
--------------------------------------------------------------------------------
1 | /*
2 | * QuickJS: Example of C module with a class
3 | *
4 | * Copyright (c) 2019 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | #include "../quickjs.h"
25 | #include
26 |
27 | #define countof(x) (sizeof(x) / sizeof((x)[0]))
28 |
29 | /* Point Class */
30 |
31 | typedef struct {
32 | int x;
33 | int y;
34 | } JSPointData;
35 |
36 | static JSClassID js_point_class_id;
37 |
38 | static void js_point_finalizer(JSRuntime *rt, JSValue val)
39 | {
40 | JSPointData *s = JS_GetOpaque(val, js_point_class_id);
41 | /* Note: 's' can be NULL in case JS_SetOpaque() was not called */
42 | js_free_rt(rt, s);
43 | }
44 |
45 | static JSValue js_point_ctor(JSContext *ctx,
46 | JSValueConst new_target,
47 | int argc, JSValueConst *argv)
48 | {
49 | JSPointData *s;
50 | JSValue obj = JS_UNDEFINED;
51 | JSValue proto;
52 |
53 | s = js_mallocz(ctx, sizeof(*s));
54 | if (!s)
55 | return JS_EXCEPTION;
56 | if (JS_ToInt32(ctx, &s->x, argv[0]))
57 | goto fail;
58 | if (JS_ToInt32(ctx, &s->y, argv[1]))
59 | goto fail;
60 | /* using new_target to get the prototype is necessary when the
61 | class is extended. */
62 | proto = JS_GetPropertyStr(ctx, new_target, "prototype");
63 | if (JS_IsException(proto))
64 | goto fail;
65 | obj = JS_NewObjectProtoClass(ctx, proto, js_point_class_id);
66 | JS_FreeValue(ctx, proto);
67 | if (JS_IsException(obj))
68 | goto fail;
69 | JS_SetOpaque(obj, s);
70 | return obj;
71 | fail:
72 | js_free(ctx, s);
73 | JS_FreeValue(ctx, obj);
74 | return JS_EXCEPTION;
75 | }
76 |
77 | static JSValue js_point_get_xy(JSContext *ctx, JSValueConst this_val, int magic)
78 | {
79 | JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
80 | if (!s)
81 | return JS_EXCEPTION;
82 | if (magic == 0)
83 | return JS_NewInt32(ctx, s->x);
84 | else
85 | return JS_NewInt32(ctx, s->y);
86 | }
87 |
88 | static JSValue js_point_set_xy(JSContext *ctx, JSValueConst this_val, JSValue val, int magic)
89 | {
90 | JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
91 | int v;
92 | if (!s)
93 | return JS_EXCEPTION;
94 | if (JS_ToInt32(ctx, &v, val))
95 | return JS_EXCEPTION;
96 | if (magic == 0)
97 | s->x = v;
98 | else
99 | s->y = v;
100 | return JS_UNDEFINED;
101 | }
102 |
103 | static JSValue js_point_norm(JSContext *ctx, JSValueConst this_val,
104 | int argc, JSValueConst *argv)
105 | {
106 | JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
107 | if (!s)
108 | return JS_EXCEPTION;
109 | return JS_NewFloat64(ctx, sqrt((double)s->x * s->x + (double)s->y * s->y));
110 | }
111 |
112 | static JSClassDef js_point_class = {
113 | "Point",
114 | .finalizer = js_point_finalizer,
115 | };
116 |
117 | static const JSCFunctionListEntry js_point_proto_funcs[] = {
118 | JS_CGETSET_MAGIC_DEF("x", js_point_get_xy, js_point_set_xy, 0),
119 | JS_CGETSET_MAGIC_DEF("y", js_point_get_xy, js_point_set_xy, 1),
120 | JS_CFUNC_DEF("norm", 0, js_point_norm),
121 | };
122 |
123 | static int js_point_init(JSContext *ctx, JSModuleDef *m)
124 | {
125 | JSValue point_proto, point_class;
126 |
127 | /* create the Point class */
128 | JS_NewClassID(&js_point_class_id);
129 | JS_NewClass(JS_GetRuntime(ctx), js_point_class_id, &js_point_class);
130 |
131 | point_proto = JS_NewObject(ctx);
132 | JS_SetPropertyFunctionList(ctx, point_proto, js_point_proto_funcs, countof(js_point_proto_funcs));
133 |
134 | point_class = JS_NewCFunction2(ctx, js_point_ctor, "Point", 2, JS_CFUNC_constructor, 0);
135 | /* set proto.constructor and ctor.prototype */
136 | JS_SetConstructor(ctx, point_class, point_proto);
137 | JS_SetClassProto(ctx, js_point_class_id, point_proto);
138 |
139 | JS_SetModuleExport(ctx, m, "Point", point_class);
140 | return 0;
141 | }
142 |
143 | JSModuleDef *js_init_module(JSContext *ctx, const char *module_name)
144 | {
145 | JSModuleDef *m;
146 | m = JS_NewCModule(ctx, module_name, js_point_init);
147 | if (!m)
148 | return NULL;
149 | JS_AddModuleExport(ctx, m, "Point");
150 | return m;
151 | }
152 |
--------------------------------------------------------------------------------
/examples/test_fib.js:
--------------------------------------------------------------------------------
1 | /* example of JS module importing a C module */
2 |
3 | import { fib } from "./fib.so";
4 |
5 | console.log("Hello World");
6 | console.log("fib(10)=", fib(10));
7 |
--------------------------------------------------------------------------------
/examples/test_point.js:
--------------------------------------------------------------------------------
1 | /* example of JS module importing a C module */
2 | import { Point } from "./point.so";
3 |
4 | function assert(b, str)
5 | {
6 | if (b) {
7 | return;
8 | } else {
9 | throw Error("assertion failed: " + str);
10 | }
11 | }
12 |
13 | class ColorPoint extends Point {
14 | constructor(x, y, color) {
15 | super(x, y);
16 | this.color = color;
17 | }
18 | get_color() {
19 | return this.color;
20 | }
21 | };
22 |
23 | function main()
24 | {
25 | var pt, pt2;
26 |
27 | pt = new Point(2, 3);
28 | assert(pt.x === 2);
29 | assert(pt.y === 3);
30 | pt.x = 4;
31 | assert(pt.x === 4);
32 | assert(pt.norm() == 5);
33 |
34 | pt2 = new ColorPoint(2, 3, 0xffffff);
35 | assert(pt2.x === 2);
36 | assert(pt2.color === 0xffffff);
37 | assert(pt2.get_color() === 0xffffff);
38 | }
39 |
40 | main();
41 |
--------------------------------------------------------------------------------
/fuzz/README:
--------------------------------------------------------------------------------
1 | libFuzzer support for QuickJS
2 | =============================
3 |
4 | Build QuickJS with libFuzzer support as follows:
5 |
6 | CONFIG_CLANG=y make libfuzzer
7 |
8 | This can be extended with sanitizer support to improve efficacy:
9 |
10 | CONFIG_CLANG=y CONFIG_ASAN=y make libfuzzer
11 |
12 |
13 | Currently, there are three fuzzing targets defined: fuzz_eval, fuzz_compile and fuzz_regexp.
14 | The above build command will produce an executable binary for each of them, which can be
15 | simply executed as:
16 |
17 | ./fuzz_eval
18 |
19 | or with an initial corpus:
20 |
21 | ./fuzz_compile corpus_dir/
22 |
23 | or with a predefined dictionary to improve its efficacy:
24 |
25 | ./fuzz_eval -dict fuzz/fuzz.dict
26 |
27 | or with arbitrary CLI arguments provided by libFuzzer (https://llvm.org/docs/LibFuzzer.html).
28 |
--------------------------------------------------------------------------------
/fuzz/fuzz.dict:
--------------------------------------------------------------------------------
1 | "__loadScript"
2 | "abs"
3 | "acos"
4 | "acosh"
5 | "add"
6 | "AggregateError"
7 | "and"
8 | "apply"
9 | "Array"
10 | "ArrayBuffer"
11 | "asin"
12 | "asinh"
13 | "atan"
14 | "atan2"
15 | "atanh"
16 | "Atomics"
17 | "BigInt"
18 | "BigInt64Array"
19 | "BigUint64Array"
20 | "Boolean"
21 | "cbrt"
22 | "ceil"
23 | "chdir"
24 | "clearTimeout"
25 | "close"
26 | "clz32"
27 | "compareExchange"
28 | "console"
29 | "construct"
30 | "cos"
31 | "cosh"
32 | "DataView"
33 | "Date"
34 | "decodeURI"
35 | "decodeURIComponent"
36 | "defineProperty"
37 | "deleteProperty"
38 | "dup"
39 | "dup2"
40 | "E"
41 | "encodeURI"
42 | "encodeURIComponent"
43 | "err"
44 | "Error"
45 | "escape"
46 | "eval"
47 | "EvalError"
48 | "evalScript"
49 | "exchange"
50 | "exec"
51 | "exit"
52 | "exp"
53 | "expm1"
54 | "fdopen"
55 | "Float32Array"
56 | "Float64Array"
57 | "floor"
58 | "fround"
59 | "Function"
60 | "gc"
61 | "get"
62 | "getcwd"
63 | "getenv"
64 | "getenviron"
65 | "getOwnPropertyDescriptor"
66 | "getpid"
67 | "getPrototypeOf"
68 | "globalThis"
69 | "has"
70 | "hypot"
71 | "imul"
72 | "in"
73 | "Infinity"
74 | "Int16Array"
75 | "Int32Array"
76 | "Int8Array"
77 | "InternalError"
78 | "isatty"
79 | "isExtensible"
80 | "isFinite"
81 | "isLockFree"
82 | "isNaN"
83 | "iterateBuiltIns"
84 | "JSON"
85 | "kill"
86 | "length"
87 | "LN10"
88 | "LN2"
89 | "load"
90 | "loadFile"
91 | "loadScript"
92 | "log"
93 | "log10"
94 | "LOG10E"
95 | "log1p"
96 | "log2"
97 | "LOG2E"
98 | "lstat"
99 | "Map"
100 | "Math"
101 | "max"
102 | "min"
103 | "mkdir"
104 | "NaN"
105 | "notify"
106 | "now"
107 | "Number"
108 | "O_APPEND"
109 | "O_CREAT"
110 | "O_EXCL"
111 | "O_RDONLY"
112 | "O_RDWR"
113 | "O_TRUNC"
114 | "O_WRONLY"
115 | "Object"
116 | "open"
117 | "Operators"
118 | "or"
119 | "os"
120 | "out"
121 | "ownKeys"
122 | "parse"
123 | "parseExtJSON"
124 | "parseFloat"
125 | "parseInt"
126 | "PI"
127 | "pipe"
128 | "platform"
129 | "popen"
130 | "pow"
131 | "preventExtensions"
132 | "print"
133 | "printf"
134 | "Promise"
135 | "Proxy"
136 | "puts"
137 | "random"
138 | "RangeError"
139 | "read"
140 | "readdir"
141 | "readlink"
142 | "realpath"
143 | "ReferenceError"
144 | "Reflect"
145 | "RegExp"
146 | "remove"
147 | "rename"
148 | "round"
149 | "S_IFBLK"
150 | "S_IFCHR"
151 | "S_IFDIR"
152 | "S_IFIFO"
153 | "S_IFLNK"
154 | "S_IFMT"
155 | "S_IFREG"
156 | "S_IFSOCK"
157 | "S_ISGID"
158 | "S_ISUID"
159 | "scriptArgs"
160 | "seek"
161 | "SEEK_CUR"
162 | "SEEK_END"
163 | "SEEK_SET"
164 | "set"
165 | "Set"
166 | "setenv"
167 | "setPrototypeOf"
168 | "setReadHandler"
169 | "setTimeout"
170 | "setWriteHandler"
171 | "SharedArrayBuffer"
172 | "SIGABRT"
173 | "SIGALRM"
174 | "SIGCHLD"
175 | "SIGCONT"
176 | "SIGFPE"
177 | "SIGILL"
178 | "SIGINT"
179 | "sign"
180 | "signal"
181 | "SIGPIPE"
182 | "SIGQUIT"
183 | "SIGSEGV"
184 | "SIGSTOP"
185 | "SIGTERM"
186 | "SIGTSTP"
187 | "SIGTTIN"
188 | "SIGTTOU"
189 | "SIGUSR1"
190 | "SIGUSR2"
191 | "sin"
192 | "sinh"
193 | "sleep"
194 | "sleepAsync"
195 | "sprintf"
196 | "sqrt"
197 | "SQRT1_2"
198 | "SQRT2"
199 | "stat"
200 | "std"
201 | "store"
202 | "strerror"
203 | "String"
204 | "stringify"
205 | "sub"
206 | "Symbol"
207 | "symlink"
208 | "SyntaxError"
209 | "tan"
210 | "tanh"
211 | "tmpfile"
212 | "trunc"
213 | "ttyGetWinSize"
214 | "ttySetRaw"
215 | "TypeError"
216 | "Uint16Array"
217 | "Uint32Array"
218 | "Uint8Array"
219 | "Uint8ClampedArray"
220 | "undefined"
221 | "unescape"
222 | "unsetenv"
223 | "URIError"
224 | "urlGet"
225 | "utimes"
226 | "wait"
227 | "waitpid"
228 | "WeakMap"
229 | "WeakSet"
230 | "WNOHANG"
231 | "Worker"
232 | "write"
233 | "xor"
234 | "v0"
235 | "v1"
236 | "v2"
237 | "v3"
238 | "v4"
239 | "v5"
240 | "v6"
241 | "v7"
242 | "v8"
243 | "v9"
244 | "v10"
245 | "v11"
246 | "v12"
247 | "v13"
248 | "v14"
249 | "v15"
250 | "v16"
251 | "v17"
252 | "v18"
253 | "v19"
254 | "v20"
255 |
--------------------------------------------------------------------------------
/fuzz/fuzz_common.c:
--------------------------------------------------------------------------------
1 | /* Copyright 2020 Google Inc.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 | */
15 |
16 | #include
17 |
18 | #include "fuzz/fuzz_common.h"
19 |
20 | // handle timeouts from infinite loops
21 | static int interrupt_handler(JSRuntime *rt, void *opaque)
22 | {
23 | nbinterrupts++;
24 | return (nbinterrupts > 100);
25 | }
26 |
27 | void reset_nbinterrupts() {
28 | nbinterrupts = 0;
29 | }
30 |
31 | void test_one_input_init(JSRuntime *rt, JSContext *ctx) {
32 | // 64 Mo
33 | JS_SetMemoryLimit(rt, 0x4000000);
34 | // 64 Kb
35 | JS_SetMaxStackSize(rt, 0x10000);
36 |
37 | JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
38 | JS_SetInterruptHandler(JS_GetRuntime(ctx), interrupt_handler, NULL);
39 | js_std_add_helpers(ctx, 0, NULL);
40 |
41 | // Load os and std
42 | js_std_init_handlers(rt);
43 | js_init_module_std(ctx, "std");
44 | js_init_module_os(ctx, "os");
45 | const char *str = "import * as std from 'std';\n"
46 | "import * as os from 'os';\n"
47 | "globalThis.std = std;\n"
48 | "globalThis.os = os;\n";
49 | JSValue std_val = JS_Eval(ctx, str, strlen(str), "", JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
50 | if (!JS_IsException(std_val)) {
51 | js_module_set_import_meta(ctx, std_val, 1, 1);
52 | std_val = JS_EvalFunction(ctx, std_val);
53 | } else {
54 | js_std_dump_error(ctx);
55 | }
56 | std_val = js_std_await(ctx, std_val);
57 | JS_FreeValue(ctx, std_val);
58 | }
59 |
--------------------------------------------------------------------------------
/fuzz/fuzz_common.h:
--------------------------------------------------------------------------------
1 | /* Copyright 2020 Google Inc.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 | */
15 |
16 | #include "quickjs.h"
17 | #include "quickjs-libc.h"
18 |
19 | static int nbinterrupts = 0;
20 |
21 | void reset_nbinterrupts();
22 | void test_one_input_init(JSRuntime *rt, JSContext *ctx);
23 |
--------------------------------------------------------------------------------
/fuzz/fuzz_compile.c:
--------------------------------------------------------------------------------
1 | /* Copyright 2020 Google Inc.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 | */
15 |
16 | #include "quickjs.h"
17 | #include "quickjs-libc.h"
18 | #include "cutils.h"
19 | #include "fuzz/fuzz_common.h"
20 |
21 | #include
22 | #include
23 |
24 |
25 | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
26 | if (size == 0)
27 | return 0;
28 |
29 | JSRuntime *rt = JS_NewRuntime();
30 | JSContext *ctx = JS_NewContext(rt);
31 | test_one_input_init(rt, ctx);
32 |
33 | uint8_t *null_terminated_data = malloc(size + 1);
34 | memcpy(null_terminated_data, data, size);
35 | null_terminated_data[size] = 0;
36 |
37 | JSValue obj = JS_Eval(ctx, (const char *)null_terminated_data, size, "", JS_EVAL_FLAG_COMPILE_ONLY | JS_EVAL_TYPE_MODULE);
38 | free(null_terminated_data);
39 | //TODO target with JS_ParseJSON
40 | if (JS_IsException(obj)) {
41 | js_std_free_handlers(rt);
42 | JS_FreeValue(ctx, obj);
43 | JS_FreeContext(ctx);
44 | JS_FreeRuntime(rt);
45 | return 0;
46 | }
47 | obj = js_std_await(ctx, obj);
48 | size_t bytecode_size;
49 | uint8_t* bytecode = JS_WriteObject(ctx, &bytecode_size, obj, JS_WRITE_OBJ_BYTECODE);
50 | JS_FreeValue(ctx, obj);
51 | if (!bytecode) {
52 | js_std_free_handlers(rt);
53 | JS_FreeContext(ctx);
54 | JS_FreeRuntime(rt);
55 | return 0;
56 | }
57 | obj = JS_ReadObject(ctx, bytecode, bytecode_size, JS_READ_OBJ_BYTECODE);
58 | js_free(ctx, bytecode);
59 | if (JS_IsException(obj)) {
60 | js_std_free_handlers(rt);
61 | JS_FreeContext(ctx);
62 | JS_FreeRuntime(rt);
63 | return 0;
64 | }
65 | reset_nbinterrupts();
66 | /* this is based on
67 | * js_std_eval_binary(ctx, bytecode, bytecode_size, 0);
68 | * modified so as not to exit on JS exception
69 | */
70 | JSValue val;
71 | if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
72 | if (JS_ResolveModule(ctx, obj) < 0) {
73 | JS_FreeValue(ctx, obj);
74 | js_std_free_handlers(rt);
75 | JS_FreeContext(ctx);
76 | JS_FreeRuntime(rt);
77 | return 0;
78 | }
79 | js_module_set_import_meta(ctx, obj, FALSE, TRUE);
80 | }
81 | val = JS_EvalFunction(ctx, obj);
82 | if (JS_IsException(val)) {
83 | js_std_dump_error(ctx);
84 | } else {
85 | js_std_loop(ctx);
86 | }
87 | JS_FreeValue(ctx, val);
88 | js_std_free_handlers(rt);
89 | JS_FreeContext(ctx);
90 | JS_FreeRuntime(rt);
91 |
92 | return 0;
93 | }
94 |
--------------------------------------------------------------------------------
/fuzz/fuzz_eval.c:
--------------------------------------------------------------------------------
1 | /* Copyright 2020 Google Inc.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 | */
15 |
16 | #include "quickjs.h"
17 | #include "quickjs-libc.h"
18 | #include "fuzz/fuzz_common.h"
19 |
20 | #include
21 | #include
22 | #include
23 |
24 | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
25 | if (size == 0)
26 | return 0;
27 |
28 | JSRuntime *rt = JS_NewRuntime();
29 | JSContext *ctx = JS_NewContext(rt);
30 | test_one_input_init(rt, ctx);
31 |
32 | uint8_t *null_terminated_data = malloc(size + 1);
33 | memcpy(null_terminated_data, data, size);
34 | null_terminated_data[size] = 0;
35 |
36 | reset_nbinterrupts();
37 | //the final 0 does not count (as in strlen)
38 | JSValue val = JS_Eval(ctx, (const char *)null_terminated_data, size, "", JS_EVAL_TYPE_GLOBAL);
39 | free(null_terminated_data);
40 | //TODO targets with JS_ParseJSON, JS_ReadObject
41 | if (!JS_IsException(val)) {
42 | js_std_loop(ctx);
43 | JS_FreeValue(ctx, val);
44 | }
45 | js_std_free_handlers(rt);
46 | JS_FreeContext(ctx);
47 | JS_FreeRuntime(rt);
48 | return 0;
49 | }
50 |
--------------------------------------------------------------------------------
/fuzz/fuzz_regexp.c:
--------------------------------------------------------------------------------
1 | /* Copyright 2020 Google Inc.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 | */
15 |
16 | #include "libregexp.h"
17 | #include "quickjs-libc.h"
18 |
19 | static int nbinterrupts = 0;
20 |
21 | int lre_check_stack_overflow(void *opaque, size_t alloca_size) { return 0; }
22 |
23 | void *lre_realloc(void *opaque, void *ptr, size_t size)
24 | {
25 | return realloc(ptr, size);
26 | }
27 |
28 | int lre_check_timeout(void *opaque)
29 | {
30 | nbinterrupts++;
31 | return (nbinterrupts > 100);
32 | }
33 |
34 | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
35 | int len, ret, i;
36 | uint8_t *bc;
37 | char error_msg[64];
38 | const uint8_t *input;
39 | uint8_t *capture[255 * 2];
40 | size_t size1 = size;
41 |
42 | //Splits buffer into 2 sub buffers delimited by null character
43 | for (i = 0; i < size; i++) {
44 | if (data[i] == 0) {
45 | size1 = i;
46 | break;
47 | }
48 | }
49 | if (size1 == size) {
50 | //missing delimiter
51 | return 0;
52 | }
53 | bc = lre_compile(&len, error_msg, sizeof(error_msg), (const char *) data,
54 | size1, 0, NULL);
55 | if (!bc) {
56 | return 0;
57 | }
58 | input = data + size1 + 1;
59 | ret = lre_exec(capture, bc, input, 0, size - (size1 + 1), 0, NULL);
60 | if (ret == 1) {
61 | lre_get_capture_count(bc);
62 | }
63 | free(bc);
64 |
65 | return 0;
66 | }
67 |
--------------------------------------------------------------------------------
/fuzz/generate_dict.js:
--------------------------------------------------------------------------------
1 | // Function to recursively iterate through built-in names.
2 | function collectBuiltinNames(obj, visited = new Set(), result = new Set()) {
3 | // Check if the object has already been visited to avoid infinite recursion.
4 | if (visited.has(obj))
5 | return;
6 |
7 | // Add the current object to the set of visited objects
8 | visited.add(obj);
9 | // Get the property names of the current object
10 | const properties = Object.getOwnPropertyNames(obj);
11 | // Iterate through each property
12 | for (var i=0; i < properties.length; i++) {
13 | var property = properties[i];
14 | if (property != "collectBuiltinNames" && typeof property != "number")
15 | result.add(property);
16 | // Check if the property is an object and if so, recursively iterate through its properties.
17 | if (typeof obj[property] === 'object' && obj[property] !== null)
18 | collectBuiltinNames(obj[property], visited, result);
19 | }
20 | return result;
21 | }
22 |
23 | // Start the recursive iteration with the global object.
24 | console.log(Array.from(collectBuiltinNames(this)).join('\n'));
25 |
--------------------------------------------------------------------------------
/libregexp-opcode.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Regular Expression Engine
3 | *
4 | * Copyright (c) 2017-2018 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | #ifdef DEF
26 |
27 | DEF(invalid, 1) /* never used */
28 | DEF(char, 3)
29 | DEF(char_i, 3)
30 | DEF(char32, 5)
31 | DEF(char32_i, 5)
32 | DEF(dot, 1)
33 | DEF(any, 1) /* same as dot but match any character including line terminator */
34 | DEF(line_start, 1)
35 | DEF(line_start_m, 1)
36 | DEF(line_end, 1)
37 | DEF(line_end_m, 1)
38 | DEF(goto, 5)
39 | DEF(split_goto_first, 5)
40 | DEF(split_next_first, 5)
41 | DEF(match, 1)
42 | DEF(save_start, 2) /* save start position */
43 | DEF(save_end, 2) /* save end position, must come after saved_start */
44 | DEF(save_reset, 3) /* reset save positions */
45 | DEF(loop, 5) /* decrement the top the stack and goto if != 0 */
46 | DEF(push_i32, 5) /* push integer on the stack */
47 | DEF(drop, 1)
48 | DEF(word_boundary, 1)
49 | DEF(word_boundary_i, 1)
50 | DEF(not_word_boundary, 1)
51 | DEF(not_word_boundary_i, 1)
52 | DEF(back_reference, 2)
53 | DEF(back_reference_i, 2) /* must come after */
54 | DEF(backward_back_reference, 2) /* must come after */
55 | DEF(backward_back_reference_i, 2) /* must come after */
56 | DEF(range, 3) /* variable length */
57 | DEF(range_i, 3) /* variable length */
58 | DEF(range32, 3) /* variable length */
59 | DEF(range32_i, 3) /* variable length */
60 | DEF(lookahead, 5)
61 | DEF(negative_lookahead, 5)
62 | DEF(push_char_pos, 1) /* push the character position on the stack */
63 | DEF(check_advance, 1) /* pop one stack element and check that it is different from the character position */
64 | DEF(prev, 1) /* go to the previous char */
65 | DEF(simple_greedy_quant, 17)
66 |
67 | #endif /* DEF */
68 |
--------------------------------------------------------------------------------
/libregexp.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Regular Expression Engine
3 | *
4 | * Copyright (c) 2017-2018 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | #ifndef LIBREGEXP_H
25 | #define LIBREGEXP_H
26 |
27 | #include
28 | #include
29 |
30 | #define LRE_FLAG_GLOBAL (1 << 0)
31 | #define LRE_FLAG_IGNORECASE (1 << 1)
32 | #define LRE_FLAG_MULTILINE (1 << 2)
33 | #define LRE_FLAG_DOTALL (1 << 3)
34 | #define LRE_FLAG_UNICODE (1 << 4)
35 | #define LRE_FLAG_STICKY (1 << 5)
36 | #define LRE_FLAG_INDICES (1 << 6) /* Unused by libregexp, just recorded. */
37 | #define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */
38 | #define LRE_FLAG_UNICODE_SETS (1 << 8)
39 |
40 | #define LRE_RET_MEMORY_ERROR (-1)
41 | #define LRE_RET_TIMEOUT (-2)
42 |
43 | uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
44 | const char *buf, size_t buf_len, int re_flags,
45 | void *opaque);
46 | int lre_get_capture_count(const uint8_t *bc_buf);
47 | int lre_get_flags(const uint8_t *bc_buf);
48 | const char *lre_get_groupnames(const uint8_t *bc_buf);
49 | int lre_exec(uint8_t **capture,
50 | const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen,
51 | int cbuf_type, void *opaque);
52 |
53 | int lre_parse_escape(const uint8_t **pp, int allow_utf16);
54 |
55 | /* must be provided by the user, return non zero if overflow */
56 | int lre_check_stack_overflow(void *opaque, size_t alloca_size);
57 | /* must be provided by the user, return non zero if time out */
58 | int lre_check_timeout(void *opaque);
59 | void *lre_realloc(void *opaque, void *ptr, size_t size);
60 |
61 | #endif /* LIBREGEXP_H */
62 |
--------------------------------------------------------------------------------
/libunicode.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Unicode utilities
3 | *
4 | * Copyright (c) 2017-2018 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | #ifndef LIBUNICODE_H
25 | #define LIBUNICODE_H
26 |
27 | #include
28 |
29 | /* define it to include all the unicode tables (40KB larger) */
30 | #define CONFIG_ALL_UNICODE
31 |
32 | #define LRE_CC_RES_LEN_MAX 3
33 |
34 | /* char ranges */
35 |
36 | typedef struct {
37 | int len; /* in points, always even */
38 | int size;
39 | uint32_t *points; /* points sorted by increasing value */
40 | void *mem_opaque;
41 | void *(*realloc_func)(void *opaque, void *ptr, size_t size);
42 | } CharRange;
43 |
44 | typedef enum {
45 | CR_OP_UNION,
46 | CR_OP_INTER,
47 | CR_OP_XOR,
48 | CR_OP_SUB,
49 | } CharRangeOpEnum;
50 |
51 | void cr_init(CharRange *cr, void *mem_opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size));
52 | void cr_free(CharRange *cr);
53 | int cr_realloc(CharRange *cr, int size);
54 | int cr_copy(CharRange *cr, const CharRange *cr1);
55 |
56 | static inline int cr_add_point(CharRange *cr, uint32_t v)
57 | {
58 | if (cr->len >= cr->size) {
59 | if (cr_realloc(cr, cr->len + 1))
60 | return -1;
61 | }
62 | cr->points[cr->len++] = v;
63 | return 0;
64 | }
65 |
66 | static inline int cr_add_interval(CharRange *cr, uint32_t c1, uint32_t c2)
67 | {
68 | if ((cr->len + 2) > cr->size) {
69 | if (cr_realloc(cr, cr->len + 2))
70 | return -1;
71 | }
72 | cr->points[cr->len++] = c1;
73 | cr->points[cr->len++] = c2;
74 | return 0;
75 | }
76 |
77 | int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
78 | const uint32_t *b_pt, int b_len, int op);
79 | int cr_op1(CharRange *cr, const uint32_t *b_pt, int b_len, int op);
80 |
81 | static inline int cr_union_interval(CharRange *cr, uint32_t c1, uint32_t c2)
82 | {
83 | uint32_t b_pt[2];
84 | b_pt[0] = c1;
85 | b_pt[1] = c2 + 1;
86 | return cr_op1(cr, b_pt, 2, CR_OP_UNION);
87 | }
88 |
89 | int cr_invert(CharRange *cr);
90 |
91 | int cr_regexp_canonicalize(CharRange *cr, int is_unicode);
92 |
93 | typedef enum {
94 | UNICODE_NFC,
95 | UNICODE_NFD,
96 | UNICODE_NFKC,
97 | UNICODE_NFKD,
98 | } UnicodeNormalizationEnum;
99 |
100 | int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
101 | UnicodeNormalizationEnum n_type,
102 | void *opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size));
103 |
104 | /* Unicode character range functions */
105 |
106 | int unicode_script(CharRange *cr, const char *script_name, int is_ext);
107 | int unicode_general_category(CharRange *cr, const char *gc_name);
108 | int unicode_prop(CharRange *cr, const char *prop_name);
109 |
110 | typedef void UnicodeSequencePropCB(void *opaque, const uint32_t *buf, int len);
111 | int unicode_sequence_prop(const char *prop_name, UnicodeSequencePropCB *cb, void *opaque,
112 | CharRange *cr);
113 |
114 | int lre_case_conv(uint32_t *res, uint32_t c, int conv_type);
115 | int lre_canonicalize(uint32_t c, int is_unicode);
116 |
117 | /* Code point type categories */
118 | enum {
119 | UNICODE_C_SPACE = (1 << 0),
120 | UNICODE_C_DIGIT = (1 << 1),
121 | UNICODE_C_UPPER = (1 << 2),
122 | UNICODE_C_LOWER = (1 << 3),
123 | UNICODE_C_UNDER = (1 << 4),
124 | UNICODE_C_DOLLAR = (1 << 5),
125 | UNICODE_C_XDIGIT = (1 << 6),
126 | };
127 | extern uint8_t const lre_ctype_bits[256];
128 |
129 | /* zero or non-zero return value */
130 | int lre_is_cased(uint32_t c);
131 | int lre_is_case_ignorable(uint32_t c);
132 | int lre_is_id_start(uint32_t c);
133 | int lre_is_id_continue(uint32_t c);
134 |
135 | static inline int lre_is_space_byte(uint8_t c) {
136 | return lre_ctype_bits[c] & UNICODE_C_SPACE;
137 | }
138 |
139 | static inline int lre_is_id_start_byte(uint8_t c) {
140 | return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER |
141 | UNICODE_C_UNDER | UNICODE_C_DOLLAR);
142 | }
143 |
144 | static inline int lre_is_id_continue_byte(uint8_t c) {
145 | return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER |
146 | UNICODE_C_UNDER | UNICODE_C_DOLLAR |
147 | UNICODE_C_DIGIT);
148 | }
149 |
150 | int lre_is_space_non_ascii(uint32_t c);
151 |
152 | static inline int lre_is_space(uint32_t c) {
153 | if (c < 256)
154 | return lre_is_space_byte(c);
155 | else
156 | return lre_is_space_non_ascii(c);
157 | }
158 |
159 | static inline int lre_js_is_ident_first(uint32_t c) {
160 | if (c < 128) {
161 | return lre_is_id_start_byte(c);
162 | } else {
163 | #ifdef CONFIG_ALL_UNICODE
164 | return lre_is_id_start(c);
165 | #else
166 | return !lre_is_space_non_ascii(c);
167 | #endif
168 | }
169 | }
170 |
171 | static inline int lre_js_is_ident_next(uint32_t c) {
172 | if (c < 128) {
173 | return lre_is_id_continue_byte(c);
174 | } else {
175 | /* ZWNJ and ZWJ are accepted in identifiers */
176 | if (c >= 0x200C && c <= 0x200D)
177 | return TRUE;
178 | #ifdef CONFIG_ALL_UNICODE
179 | return lre_is_id_continue(c);
180 | #else
181 | return !lre_is_space_non_ascii(c);
182 | #endif
183 | }
184 | }
185 |
186 | #endif /* LIBUNICODE_H */
187 |
--------------------------------------------------------------------------------
/list.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Linux klist like system
3 | *
4 | * Copyright (c) 2016-2017 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | #ifndef LIST_H
25 | #define LIST_H
26 |
27 | #ifndef NULL
28 | #include
29 | #endif
30 |
31 | struct list_head {
32 | struct list_head *prev;
33 | struct list_head *next;
34 | };
35 |
36 | #define LIST_HEAD_INIT(el) { &(el), &(el) }
37 |
38 | /* return the pointer of type 'type *' containing 'el' as field 'member' */
39 | #define list_entry(el, type, member) container_of(el, type, member)
40 |
41 | static inline void init_list_head(struct list_head *head)
42 | {
43 | head->prev = head;
44 | head->next = head;
45 | }
46 |
47 | /* insert 'el' between 'prev' and 'next' */
48 | static inline void __list_add(struct list_head *el,
49 | struct list_head *prev, struct list_head *next)
50 | {
51 | prev->next = el;
52 | el->prev = prev;
53 | el->next = next;
54 | next->prev = el;
55 | }
56 |
57 | /* add 'el' at the head of the list 'head' (= after element head) */
58 | static inline void list_add(struct list_head *el, struct list_head *head)
59 | {
60 | __list_add(el, head, head->next);
61 | }
62 |
63 | /* add 'el' at the end of the list 'head' (= before element head) */
64 | static inline void list_add_tail(struct list_head *el, struct list_head *head)
65 | {
66 | __list_add(el, head->prev, head);
67 | }
68 |
69 | static inline void list_del(struct list_head *el)
70 | {
71 | struct list_head *prev, *next;
72 | prev = el->prev;
73 | next = el->next;
74 | prev->next = next;
75 | next->prev = prev;
76 | el->prev = NULL; /* fail safe */
77 | el->next = NULL; /* fail safe */
78 | }
79 |
80 | static inline int list_empty(struct list_head *el)
81 | {
82 | return el->next == el;
83 | }
84 |
85 | #define list_for_each(el, head) \
86 | for(el = (head)->next; el != (head); el = el->next)
87 |
88 | #define list_for_each_safe(el, el1, head) \
89 | for(el = (head)->next, el1 = el->next; el != (head); \
90 | el = el1, el1 = el->next)
91 |
92 | #define list_for_each_prev(el, head) \
93 | for(el = (head)->prev; el != (head); el = el->prev)
94 |
95 | #define list_for_each_prev_safe(el, el1, head) \
96 | for(el = (head)->prev, el1 = el->prev; el != (head); \
97 | el = el1, el1 = el->prev)
98 |
99 | #endif /* LIST_H */
100 |
--------------------------------------------------------------------------------
/quickjs-atom.h:
--------------------------------------------------------------------------------
1 | /*
2 | * QuickJS atom definitions
3 | *
4 | * Copyright (c) 2017-2018 Fabrice Bellard
5 | * Copyright (c) 2017-2018 Charlie Gordon
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | */
25 |
26 | #ifdef DEF
27 |
28 | /* Note: first atoms are considered as keywords in the parser */
29 | DEF(null, "null") /* must be first */
30 | DEF(false, "false")
31 | DEF(true, "true")
32 | DEF(if, "if")
33 | DEF(else, "else")
34 | DEF(return, "return")
35 | DEF(var, "var")
36 | DEF(this, "this")
37 | DEF(delete, "delete")
38 | DEF(void, "void")
39 | DEF(typeof, "typeof")
40 | DEF(new, "new")
41 | DEF(in, "in")
42 | DEF(instanceof, "instanceof")
43 | DEF(do, "do")
44 | DEF(while, "while")
45 | DEF(for, "for")
46 | DEF(break, "break")
47 | DEF(continue, "continue")
48 | DEF(switch, "switch")
49 | DEF(case, "case")
50 | DEF(default, "default")
51 | DEF(throw, "throw")
52 | DEF(try, "try")
53 | DEF(catch, "catch")
54 | DEF(finally, "finally")
55 | DEF(function, "function")
56 | DEF(debugger, "debugger")
57 | DEF(with, "with")
58 | /* FutureReservedWord */
59 | DEF(class, "class")
60 | DEF(const, "const")
61 | DEF(enum, "enum")
62 | DEF(export, "export")
63 | DEF(extends, "extends")
64 | DEF(import, "import")
65 | DEF(super, "super")
66 | /* FutureReservedWords when parsing strict mode code */
67 | DEF(implements, "implements")
68 | DEF(interface, "interface")
69 | DEF(let, "let")
70 | DEF(package, "package")
71 | DEF(private, "private")
72 | DEF(protected, "protected")
73 | DEF(public, "public")
74 | DEF(static, "static")
75 | DEF(yield, "yield")
76 | DEF(await, "await")
77 |
78 | /* empty string */
79 | DEF(empty_string, "")
80 | /* identifiers */
81 | DEF(length, "length")
82 | DEF(fileName, "fileName")
83 | DEF(lineNumber, "lineNumber")
84 | DEF(columnNumber, "columnNumber")
85 | DEF(message, "message")
86 | DEF(cause, "cause")
87 | DEF(errors, "errors")
88 | DEF(stack, "stack")
89 | DEF(name, "name")
90 | DEF(toString, "toString")
91 | DEF(toLocaleString, "toLocaleString")
92 | DEF(valueOf, "valueOf")
93 | DEF(eval, "eval")
94 | DEF(prototype, "prototype")
95 | DEF(constructor, "constructor")
96 | DEF(configurable, "configurable")
97 | DEF(writable, "writable")
98 | DEF(enumerable, "enumerable")
99 | DEF(value, "value")
100 | DEF(get, "get")
101 | DEF(set, "set")
102 | DEF(of, "of")
103 | DEF(__proto__, "__proto__")
104 | DEF(undefined, "undefined")
105 | DEF(number, "number")
106 | DEF(boolean, "boolean")
107 | DEF(string, "string")
108 | DEF(object, "object")
109 | DEF(symbol, "symbol")
110 | DEF(integer, "integer")
111 | DEF(unknown, "unknown")
112 | DEF(arguments, "arguments")
113 | DEF(callee, "callee")
114 | DEF(caller, "caller")
115 | DEF(_eval_, "")
116 | DEF(_ret_, "")
117 | DEF(_var_, "")
118 | DEF(_arg_var_, "")
119 | DEF(_with_, "")
120 | DEF(lastIndex, "lastIndex")
121 | DEF(target, "target")
122 | DEF(index, "index")
123 | DEF(input, "input")
124 | DEF(defineProperties, "defineProperties")
125 | DEF(apply, "apply")
126 | DEF(join, "join")
127 | DEF(concat, "concat")
128 | DEF(split, "split")
129 | DEF(construct, "construct")
130 | DEF(getPrototypeOf, "getPrototypeOf")
131 | DEF(setPrototypeOf, "setPrototypeOf")
132 | DEF(isExtensible, "isExtensible")
133 | DEF(preventExtensions, "preventExtensions")
134 | DEF(has, "has")
135 | DEF(deleteProperty, "deleteProperty")
136 | DEF(defineProperty, "defineProperty")
137 | DEF(getOwnPropertyDescriptor, "getOwnPropertyDescriptor")
138 | DEF(ownKeys, "ownKeys")
139 | DEF(add, "add")
140 | DEF(done, "done")
141 | DEF(next, "next")
142 | DEF(values, "values")
143 | DEF(source, "source")
144 | DEF(flags, "flags")
145 | DEF(global, "global")
146 | DEF(unicode, "unicode")
147 | DEF(raw, "raw")
148 | DEF(new_target, "new.target")
149 | DEF(this_active_func, "this.active_func")
150 | DEF(home_object, "")
151 | DEF(computed_field, "")
152 | DEF(static_computed_field, "") /* must come after computed_fields */
153 | DEF(class_fields_init, "")
154 | DEF(brand, "")
155 | DEF(hash_constructor, "#constructor")
156 | DEF(as, "as")
157 | DEF(from, "from")
158 | DEF(meta, "meta")
159 | DEF(_default_, "*default*")
160 | DEF(_star_, "*")
161 | DEF(Module, "Module")
162 | DEF(then, "then")
163 | DEF(resolve, "resolve")
164 | DEF(reject, "reject")
165 | DEF(promise, "promise")
166 | DEF(proxy, "proxy")
167 | DEF(revoke, "revoke")
168 | DEF(async, "async")
169 | DEF(exec, "exec")
170 | DEF(groups, "groups")
171 | DEF(indices, "indices")
172 | DEF(status, "status")
173 | DEF(reason, "reason")
174 | DEF(globalThis, "globalThis")
175 | DEF(bigint, "bigint")
176 | DEF(minus_zero, "-0")
177 | DEF(Infinity, "Infinity")
178 | DEF(minus_Infinity, "-Infinity")
179 | DEF(NaN, "NaN")
180 | DEF(hasIndices, "hasIndices")
181 | DEF(ignoreCase, "ignoreCase")
182 | DEF(multiline, "multiline")
183 | DEF(dotAll, "dotAll")
184 | DEF(sticky, "sticky")
185 | DEF(unicodeSets, "unicodeSets")
186 | /* the following 3 atoms are only used with CONFIG_ATOMICS */
187 | DEF(not_equal, "not-equal")
188 | DEF(timed_out, "timed-out")
189 | DEF(ok, "ok")
190 | /* */
191 | DEF(toJSON, "toJSON")
192 | /* class names */
193 | DEF(Object, "Object")
194 | DEF(Array, "Array")
195 | DEF(Error, "Error")
196 | DEF(Number, "Number")
197 | DEF(String, "String")
198 | DEF(Boolean, "Boolean")
199 | DEF(Symbol, "Symbol")
200 | DEF(Arguments, "Arguments")
201 | DEF(Math, "Math")
202 | DEF(JSON, "JSON")
203 | DEF(Date, "Date")
204 | DEF(Function, "Function")
205 | DEF(GeneratorFunction, "GeneratorFunction")
206 | DEF(ForInIterator, "ForInIterator")
207 | DEF(RegExp, "RegExp")
208 | DEF(ArrayBuffer, "ArrayBuffer")
209 | DEF(SharedArrayBuffer, "SharedArrayBuffer")
210 | /* must keep same order as class IDs for typed arrays */
211 | DEF(Uint8ClampedArray, "Uint8ClampedArray")
212 | DEF(Int8Array, "Int8Array")
213 | DEF(Uint8Array, "Uint8Array")
214 | DEF(Int16Array, "Int16Array")
215 | DEF(Uint16Array, "Uint16Array")
216 | DEF(Int32Array, "Int32Array")
217 | DEF(Uint32Array, "Uint32Array")
218 | DEF(BigInt64Array, "BigInt64Array")
219 | DEF(BigUint64Array, "BigUint64Array")
220 | DEF(Float16Array, "Float16Array")
221 | DEF(Float32Array, "Float32Array")
222 | DEF(Float64Array, "Float64Array")
223 | DEF(DataView, "DataView")
224 | DEF(BigInt, "BigInt")
225 | DEF(WeakRef, "WeakRef")
226 | DEF(FinalizationRegistry, "FinalizationRegistry")
227 | DEF(Map, "Map")
228 | DEF(Set, "Set") /* Map + 1 */
229 | DEF(WeakMap, "WeakMap") /* Map + 2 */
230 | DEF(WeakSet, "WeakSet") /* Map + 3 */
231 | DEF(Map_Iterator, "Map Iterator")
232 | DEF(Set_Iterator, "Set Iterator")
233 | DEF(Array_Iterator, "Array Iterator")
234 | DEF(String_Iterator, "String Iterator")
235 | DEF(RegExp_String_Iterator, "RegExp String Iterator")
236 | DEF(Generator, "Generator")
237 | DEF(Proxy, "Proxy")
238 | DEF(Promise, "Promise")
239 | DEF(PromiseResolveFunction, "PromiseResolveFunction")
240 | DEF(PromiseRejectFunction, "PromiseRejectFunction")
241 | DEF(AsyncFunction, "AsyncFunction")
242 | DEF(AsyncFunctionResolve, "AsyncFunctionResolve")
243 | DEF(AsyncFunctionReject, "AsyncFunctionReject")
244 | DEF(AsyncGeneratorFunction, "AsyncGeneratorFunction")
245 | DEF(AsyncGenerator, "AsyncGenerator")
246 | DEF(EvalError, "EvalError")
247 | DEF(RangeError, "RangeError")
248 | DEF(ReferenceError, "ReferenceError")
249 | DEF(SyntaxError, "SyntaxError")
250 | DEF(TypeError, "TypeError")
251 | DEF(URIError, "URIError")
252 | DEF(InternalError, "InternalError")
253 | /* private symbols */
254 | DEF(Private_brand, "")
255 | /* symbols */
256 | DEF(Symbol_toPrimitive, "Symbol.toPrimitive")
257 | DEF(Symbol_iterator, "Symbol.iterator")
258 | DEF(Symbol_match, "Symbol.match")
259 | DEF(Symbol_matchAll, "Symbol.matchAll")
260 | DEF(Symbol_replace, "Symbol.replace")
261 | DEF(Symbol_search, "Symbol.search")
262 | DEF(Symbol_split, "Symbol.split")
263 | DEF(Symbol_toStringTag, "Symbol.toStringTag")
264 | DEF(Symbol_isConcatSpreadable, "Symbol.isConcatSpreadable")
265 | DEF(Symbol_hasInstance, "Symbol.hasInstance")
266 | DEF(Symbol_species, "Symbol.species")
267 | DEF(Symbol_unscopables, "Symbol.unscopables")
268 | DEF(Symbol_asyncIterator, "Symbol.asyncIterator")
269 |
270 | #endif /* DEF */
271 |
--------------------------------------------------------------------------------
/quickjs-libc.h:
--------------------------------------------------------------------------------
1 | /*
2 | * QuickJS C library
3 | *
4 | * Copyright (c) 2017-2018 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | #ifndef QUICKJS_LIBC_H
25 | #define QUICKJS_LIBC_H
26 |
27 | #include
28 | #include
29 |
30 | #include "quickjs.h"
31 |
32 | #ifdef __cplusplus
33 | extern "C" {
34 | #endif
35 |
36 | JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name);
37 | JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name);
38 | void js_std_add_helpers(JSContext *ctx, int argc, char **argv);
39 | void js_std_loop(JSContext *ctx);
40 | JSValue js_std_await(JSContext *ctx, JSValue obj);
41 | void js_std_init_handlers(JSRuntime *rt);
42 | void js_std_free_handlers(JSRuntime *rt);
43 | void js_std_dump_error(JSContext *ctx);
44 | uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename);
45 | int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
46 | JS_BOOL use_realpath, JS_BOOL is_main);
47 | int js_module_test_json(JSContext *ctx, JSValueConst attributes);
48 | int js_module_check_attributes(JSContext *ctx, void *opaque, JSValueConst attributes);
49 | JSModuleDef *js_module_loader(JSContext *ctx,
50 | const char *module_name, void *opaque,
51 | JSValueConst attributes);
52 | void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
53 | int flags);
54 | void js_std_eval_binary_json_module(JSContext *ctx,
55 | const uint8_t *buf, size_t buf_len,
56 | const char *module_name);
57 | void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
58 | JSValueConst reason,
59 | JS_BOOL is_handled, void *opaque);
60 | void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt));
61 |
62 | #ifdef __cplusplus
63 | } /* extern "C" { */
64 | #endif
65 |
66 | #endif /* QUICKJS_LIBC_H */
67 |
--------------------------------------------------------------------------------
/readme-cosmo.txt:
--------------------------------------------------------------------------------
1 | The executables included in this archive run on Linux, Mac, Windows,
2 | FreeBSD, OpenBSD and NetBSD for both the ARM64 and x86_64
3 | architectures.
4 |
5 | Platform Notes:
6 |
7 | - if you get errors on Linux, you should disable the binfmt_misc
8 | module which automatically invokes wine with Windows executable:
9 |
10 | sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/cli' # remove Ubuntu's MZ interpreter
11 | sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/status' # remove ALL binfmt_misc entries
12 |
13 | - Under Windows, you can rename the executables with a .exe extension.
14 |
15 | - Use the --assimilate option to build a platform specific binary for
16 | better startup time:
17 |
18 | ./qjs --assimilate
19 |
20 | - See https://github.com/jart/cosmopolitan for more information about
21 | platform specific issues.
22 |
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 | The main documentation is in doc/quickjs.pdf or doc/quickjs.html.
2 |
--------------------------------------------------------------------------------
/release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # Release the QuickJS source code
3 |
4 | set -e
5 |
6 | version=`cat VERSION`
7 |
8 | if [ "$1" = "-h" ] ; then
9 | echo "release.sh [release_list]"
10 | echo ""
11 | echo "release_list: extras binary win_binary cosmo_binary quickjs"
12 |
13 | exit 1
14 | fi
15 |
16 | release_list="extras binary win_binary cosmo_binary quickjs"
17 |
18 | if [ "$1" != "" ] ; then
19 | release_list="$1"
20 | fi
21 |
22 | #################################################"
23 | # extras
24 |
25 | if echo $release_list | grep -w -q extras ; then
26 |
27 | d="quickjs-${version}"
28 | name="quickjs-extras-${version}"
29 | outdir="/tmp/${d}"
30 |
31 | rm -rf $outdir
32 | mkdir -p $outdir $outdir/unicode $outdir/tests
33 |
34 | cp unicode/* $outdir/unicode
35 | cp -a tests/bench-v8 $outdir/tests
36 |
37 | ( cd /tmp && tar Jcvf /tmp/${name}.tar.xz ${d} )
38 |
39 | fi
40 |
41 | #################################################"
42 | # Windows binary release
43 |
44 | if echo $release_list | grep -w -q win_binary ; then
45 |
46 | # win64
47 |
48 | dlldir=/usr/x86_64-w64-mingw32/sys-root/mingw/bin
49 | cross_prefix="x86_64-w64-mingw32-"
50 | d="quickjs-win-x86_64-${version}"
51 | outdir="/tmp/${d}"
52 |
53 | rm -rf $outdir
54 | mkdir -p $outdir
55 |
56 | make clean
57 | make CONFIG_WIN32=y clean
58 |
59 | make CONFIG_WIN32=y CONFIG_LTO=y qjs.exe
60 | cp qjs.exe $outdir
61 | ${cross_prefix}strip $outdir/qjs.exe
62 | cp $dlldir/libwinpthread-1.dll $outdir
63 |
64 | ( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
65 |
66 | make CONFIG_WIN32=y clean
67 |
68 | # win32
69 |
70 | dlldir=/usr/i686-w64-mingw32/sys-root/mingw/bin
71 | cross_prefix="i686-w64-mingw32-"
72 | d="quickjs-win-i686-${version}"
73 | outdir="/tmp/${d}"
74 |
75 | rm -rf $outdir
76 | mkdir -p $outdir
77 |
78 | make clean
79 | make CONFIG_WIN32=y clean
80 |
81 | make CONFIG_WIN32=y CONFIG_M32=y CONFIG_LTO=y qjs.exe
82 | cp qjs.exe $outdir
83 | ${cross_prefix}strip $outdir/qjs.exe
84 | cp $dlldir/libwinpthread-1.dll $outdir
85 |
86 | ( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
87 |
88 | fi
89 |
90 | #################################################"
91 | # Linux binary release
92 |
93 | if echo $release_list | grep -w -q binary ; then
94 |
95 | make clean
96 | make CONFIG_WIN32=y clean
97 | make -j4 CONFIG_LTO=y qjs run-test262
98 | strip qjs run-test262
99 |
100 | d="quickjs-linux-x86_64-${version}"
101 | outdir="/tmp/${d}"
102 |
103 | rm -rf $outdir
104 | mkdir -p $outdir
105 |
106 | cp qjs run-test262 $outdir
107 |
108 | ( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
109 |
110 | make clean
111 | make -j4 CONFIG_LTO=y CONFIG_M32=y qjs run-test262
112 | strip qjs run-test262
113 |
114 | d="quickjs-linux-i686-${version}"
115 | outdir="/tmp/${d}"
116 |
117 | rm -rf $outdir
118 | mkdir -p $outdir
119 |
120 | cp qjs run-test262 $outdir
121 |
122 | ( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
123 |
124 | fi
125 |
126 | #################################################"
127 | # Cosmopolitan binary release
128 |
129 | if echo $release_list | grep -w -q cosmo_binary ; then
130 |
131 | export PATH=$PATH:$HOME/cosmocc/bin
132 |
133 | d="quickjs-cosmo-${version}"
134 | outdir="/tmp/${d}"
135 |
136 | rm -rf $outdir
137 | mkdir -p $outdir
138 |
139 | make clean
140 | make CONFIG_COSMO=y -j4 qjs run-test262
141 | cp qjs run-test262 $outdir
142 | cp readme-cosmo.txt $outdir/readme.txt
143 |
144 | ( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
145 |
146 | fi
147 |
148 | #################################################"
149 | # quickjs
150 |
151 | if echo $release_list | grep -w -q quickjs ; then
152 |
153 | make build_doc
154 |
155 | d="quickjs-${version}"
156 | outdir="/tmp/${d}"
157 |
158 | rm -rf $outdir
159 | mkdir -p $outdir $outdir/doc $outdir/tests $outdir/examples
160 |
161 | cp Makefile VERSION TODO Changelog readme.txt LICENSE \
162 | release.sh unicode_download.sh \
163 | qjs.c qjsc.c repl.js \
164 | quickjs.c quickjs.h quickjs-atom.h \
165 | quickjs-libc.c quickjs-libc.h quickjs-opcode.h \
166 | cutils.c cutils.h list.h \
167 | libregexp.c libregexp.h libregexp-opcode.h \
168 | libunicode.c libunicode.h libunicode-table.h \
169 | dtoa.c dtoa.h \
170 | unicode_gen.c unicode_gen_def.h \
171 | run-test262.c test262o.conf test262.conf \
172 | test262o_errors.txt test262_errors.txt \
173 | $outdir
174 |
175 | cp tests/*.js tests/*.patch tests/bjson.c $outdir/tests
176 |
177 | cp examples/*.js examples/*.c $outdir/examples
178 |
179 | cp doc/quickjs.texi doc/quickjs.pdf doc/quickjs.html \
180 | $outdir/doc
181 |
182 | ( cd /tmp && tar Jcvf /tmp/${d}.tar.xz ${d} )
183 |
184 | fi
185 |
--------------------------------------------------------------------------------
/test262.conf:
--------------------------------------------------------------------------------
1 | [config]
2 | # general settings for test262 ES6 version
3 |
4 | # framework style: old, new
5 | style=new
6 |
7 | # handle tests tagged as [noStrict]: yes, no, skip
8 | nostrict=yes
9 |
10 | # handle tests tagged as [strictOnly]: yes, no, skip
11 | strict=yes
12 |
13 | # test mode: default, default-nostrict, default-strict, strict, nostrict, both, all
14 | mode=default
15 |
16 | # handle tests flagged as [async]: yes, no, skip
17 | # for these, load 'harness/doneprintHandle.js' prior to test
18 | # and expect `print('Test262:AsyncTestComplete')` to be called for
19 | # successful termination
20 | async=yes
21 |
22 | # handle tests flagged as [module]: yes, no, skip
23 | module=yes
24 |
25 | # output error messages: yes, no
26 | verbose=yes
27 |
28 | # load harness files from this directory
29 | harnessdir=test262/harness
30 |
31 | # names of harness include files to skip
32 | #harnessexclude=
33 |
34 | # name of the error file for known errors
35 | errorfile=test262_errors.txt
36 |
37 | # exclude tests enumerated in this file (see also [exclude] section)
38 | #excludefile=test262_exclude.txt
39 |
40 | # report test results to this file
41 | reportfile=test262_report.txt
42 |
43 | # enumerate tests from this directory
44 | testdir=test262/test
45 |
46 | [features]
47 | # Standard language features and proposed extensions
48 | # list the features that are included
49 | # skipped features are tagged as such to avoid warnings
50 | # Keep this list alpha-sorted (:sort i in vim)
51 |
52 | __getter__
53 | __proto__
54 | __setter__
55 | AggregateError
56 | align-detached-buffer-semantics-with-web-reality
57 | arbitrary-module-namespace-names=skip
58 | array-find-from-last
59 | array-grouping
60 | Array.fromAsync=skip
61 | Array.prototype.at
62 | Array.prototype.flat
63 | Array.prototype.flatMap
64 | Array.prototype.includes
65 | Array.prototype.values
66 | ArrayBuffer
67 | arraybuffer-transfer=skip
68 | arrow-function
69 | async-functions
70 | async-iteration
71 | Atomics
72 | Atomics.pause=skip
73 | Atomics.waitAsync=skip
74 | BigInt
75 | caller
76 | canonical-tz=skip
77 | change-array-by-copy
78 | class
79 | class-fields-private
80 | class-fields-private-in
81 | class-fields-public
82 | class-methods-private
83 | class-static-block
84 | class-static-fields-private
85 | class-static-fields-public
86 | class-static-methods-private
87 | coalesce-expression
88 | computed-property-names
89 | const
90 | cross-realm
91 | DataView
92 | DataView.prototype.getFloat32
93 | DataView.prototype.getFloat64
94 | DataView.prototype.getInt16
95 | DataView.prototype.getInt32
96 | DataView.prototype.getInt8
97 | DataView.prototype.getUint16
98 | DataView.prototype.getUint32
99 | DataView.prototype.setUint8
100 | decorators=skip
101 | default-parameters
102 | destructuring-assignment
103 | destructuring-binding
104 | dynamic-import
105 | error-cause
106 | Error.isError=skip
107 | explicit-resource-management=skip
108 | exponentiation
109 | export-star-as-namespace-from-module
110 | FinalizationRegistry
111 | Float16Array
112 | Float32Array
113 | Float64Array
114 | for-in-order
115 | for-of
116 | generators
117 | globalThis
118 | hashbang
119 | import-attributes
120 | import-defer=skip
121 | import.meta
122 | Int16Array
123 | Int32Array
124 | Int8Array
125 | Intl-enumeration=skip
126 | intl-normative-optional=skip
127 | Intl.DateTimeFormat-datetimestyle=skip
128 | Intl.DateTimeFormat-dayPeriod=skip
129 | Intl.DateTimeFormat-extend-timezonename=skip
130 | Intl.DateTimeFormat-formatRange=skip
131 | Intl.DateTimeFormat-fractionalSecondDigits=skip
132 | Intl.DisplayNames-v2=skip
133 | Intl.DisplayNames=skip
134 | Intl.DurationFormat=skip
135 | Intl.ListFormat=skip
136 | Intl.Locale-info=skip
137 | Intl.Locale=skip
138 | Intl.NumberFormat-unified=skip
139 | Intl.NumberFormat-v3=skip
140 | Intl.RelativeTimeFormat=skip
141 | Intl.Segmenter=skip
142 | IsHTMLDDA
143 | iterator-helpers=skip
144 | iterator-sequencing=skip
145 | json-modules
146 | json-parse-with-source=skip
147 | json-superset
148 | legacy-regexp=skip
149 | let
150 | logical-assignment-operators
151 | Map
152 | Math.sumPrecise=skip
153 | new.target
154 | numeric-separator-literal
155 | object-rest
156 | object-spread
157 | Object.fromEntries
158 | Object.hasOwn
159 | Object.is
160 | optional-catch-binding
161 | optional-chaining
162 | Promise
163 | promise-try
164 | promise-with-resolvers
165 | Promise.allSettled
166 | Promise.any
167 | Promise.prototype.finally
168 | Proxy
169 | proxy-missing-checks
170 | Reflect
171 | Reflect.construct
172 | Reflect.set
173 | Reflect.setPrototypeOf
174 | regexp-dotall
175 | regexp-duplicate-named-groups=skip
176 | regexp-lookbehind
177 | regexp-match-indices
178 | regexp-modifiers
179 | regexp-named-groups
180 | regexp-unicode-property-escapes
181 | regexp-v-flag
182 | RegExp.escape
183 | resizable-arraybuffer=skip
184 | rest-parameters
185 | Set
186 | set-methods=skip
187 | ShadowRealm=skip
188 | SharedArrayBuffer
189 | source-phase-imports-module-source=skip
190 | source-phase-imports=skip
191 | string-trimming
192 | String.fromCodePoint
193 | String.prototype.at
194 | String.prototype.endsWith
195 | String.prototype.includes
196 | String.prototype.isWellFormed
197 | String.prototype.matchAll
198 | String.prototype.replaceAll
199 | String.prototype.toWellFormed
200 | String.prototype.trimEnd
201 | String.prototype.trimStart
202 | super
203 | Symbol
204 | Symbol.asyncIterator
205 | Symbol.hasInstance
206 | Symbol.isConcatSpreadable
207 | Symbol.iterator
208 | Symbol.match
209 | Symbol.matchAll
210 | Symbol.prototype.description
211 | Symbol.replace
212 | Symbol.search
213 | Symbol.species
214 | Symbol.split
215 | Symbol.toPrimitive
216 | Symbol.toStringTag
217 | Symbol.unscopables
218 | symbols-as-weakmap-keys
219 | tail-call-optimization=skip
220 | template
221 | Temporal=skip
222 | top-level-await
223 | TypedArray
224 | TypedArray.prototype.at
225 | u180e
226 | Uint16Array
227 | Uint32Array
228 | Uint8Array
229 | uint8array-base64=skip
230 | Uint8ClampedArray
231 | upsert=skip
232 | WeakMap
233 | WeakRef
234 | WeakSet
235 | well-formed-json-stringify
236 |
237 | [exclude]
238 | # list excluded tests and directories here
239 |
240 | # intl not supported
241 | test262/test/intl402/
242 |
243 | # incompatible with the "caller" feature
244 | test262/test/built-ins/Function/prototype/restricted-property-caller.js
245 | test262/test/built-ins/Function/prototype/restricted-property-arguments.js
246 | test262/test/built-ins/ThrowTypeError/unique-per-realm-function-proto.js
247 |
248 | # slow tests
249 | #test262/test/built-ins/RegExp/CharacterClassEscapes/
250 | #test262/test/built-ins/RegExp/property-escapes/
251 |
252 | # not yet in official specification
253 | test262/test/built-ins/String/prototype/match/cstm-matcher-on-bigint-primitive.js
254 | test262/test/built-ins/String/prototype/match/cstm-matcher-on-bigint-primitive.js
255 | test262/test/built-ins/String/prototype/match/cstm-matcher-on-boolean-primitive.js
256 | test262/test/built-ins/String/prototype/match/cstm-matcher-on-boolean-primitive.js
257 | test262/test/built-ins/String/prototype/match/cstm-matcher-on-number-primitive.js
258 | test262/test/built-ins/String/prototype/match/cstm-matcher-on-number-primitive.js
259 | test262/test/built-ins/String/prototype/match/cstm-matcher-on-string-primitive.js
260 | test262/test/built-ins/String/prototype/match/cstm-matcher-on-string-primitive.js
261 | test262/test/built-ins/String/prototype/matchAll/cstm-matchall-on-bigint-primitive.js
262 | test262/test/built-ins/String/prototype/matchAll/cstm-matchall-on-bigint-primitive.js
263 | test262/test/built-ins/String/prototype/matchAll/cstm-matchall-on-number-primitive.js
264 | test262/test/built-ins/String/prototype/matchAll/cstm-matchall-on-number-primitive.js
265 | test262/test/built-ins/String/prototype/matchAll/cstm-matchall-on-string-primitive.js
266 | test262/test/built-ins/String/prototype/matchAll/cstm-matchall-on-string-primitive.js
267 | test262/test/built-ins/String/prototype/replace/cstm-replace-on-bigint-primitive.js
268 | test262/test/built-ins/String/prototype/replace/cstm-replace-on-bigint-primitive.js
269 | test262/test/built-ins/String/prototype/replace/cstm-replace-on-boolean-primitive.js
270 | test262/test/built-ins/String/prototype/replace/cstm-replace-on-boolean-primitive.js
271 | test262/test/built-ins/String/prototype/replace/cstm-replace-on-number-primitive.js
272 | test262/test/built-ins/String/prototype/replace/cstm-replace-on-number-primitive.js
273 | test262/test/built-ins/String/prototype/replace/cstm-replace-on-string-primitive.js
274 | test262/test/built-ins/String/prototype/replace/cstm-replace-on-string-primitive.js
275 | test262/test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-bigint-primitive.js
276 | test262/test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-bigint-primitive.js
277 | test262/test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-boolean-primitive.js
278 | test262/test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-boolean-primitive.js
279 | test262/test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-number-primitive.js
280 | test262/test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-number-primitive.js
281 | test262/test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-string-primitive.js
282 | test262/test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-string-primitive.js
283 | test262/test/built-ins/String/prototype/search/cstm-search-on-bigint-primitive.js
284 | test262/test/built-ins/String/prototype/search/cstm-search-on-bigint-primitive.js
285 | test262/test/built-ins/String/prototype/search/cstm-search-on-boolean-primitive.js
286 | test262/test/built-ins/String/prototype/search/cstm-search-on-boolean-primitive.js
287 | test262/test/built-ins/String/prototype/search/cstm-search-on-number-primitive.js
288 | test262/test/built-ins/String/prototype/search/cstm-search-on-number-primitive.js
289 | test262/test/built-ins/String/prototype/search/cstm-search-on-string-primitive.js
290 | test262/test/built-ins/String/prototype/search/cstm-search-on-string-primitive.js
291 | test262/test/built-ins/String/prototype/split/cstm-split-on-bigint-primitive.js
292 | test262/test/built-ins/String/prototype/split/cstm-split-on-bigint-primitive.js
293 | test262/test/built-ins/String/prototype/split/cstm-split-on-boolean-primitive.js
294 | test262/test/built-ins/String/prototype/split/cstm-split-on-boolean-primitive.js
295 | test262/test/built-ins/String/prototype/split/cstm-split-on-number-primitive.js
296 | test262/test/built-ins/String/prototype/split/cstm-split-on-number-primitive.js
297 | test262/test/built-ins/String/prototype/split/cstm-split-on-string-primitive.js
298 | test262/test/built-ins/String/prototype/split/cstm-split-on-string-primitive.js
299 |
300 | ####################################
301 | # staging tests
302 |
303 | # sort() does not modify the array and we don't update it (XXX: the
304 | # spec updates it in this case)
305 | test262/test/staging/sm/Array/frozen-dense-array.js
306 |
307 | # not supported
308 | test262/test/staging/sm/Set/difference.js
309 | test262/test/staging/sm/Set/intersection.js
310 | test262/test/staging/sm/Set/is-disjoint-from.js
311 | test262/test/staging/sm/Set/is-subset-of.js
312 | test262/test/staging/sm/Set/is-superset-of.js
313 | test262/test/staging/sm/Set/symmetric-difference.js
314 | test262/test/staging/sm/Set/union.js
315 | test262/test/staging/sm/extensions/censor-strict-caller.js
316 | test262/test/staging/sm/JSON/parse-with-source.js
317 |
318 | # not standard
319 | test262/test/staging/sm/Function/builtin-no-construct.js
320 | test262/test/staging/sm/Function/function-caller-restrictions.js
321 | test262/test/staging/sm/Function/function-toString-builtin-name.js
322 | test262/test/staging/sm/extensions/arguments-property-access-in-function.js
323 | test262/test/staging/sm/extensions/function-caller-skips-eval-frames.js
324 | test262/test/staging/sm/extensions/function-properties.js
325 | test262/test/staging/sm/regress/regress-577648-1.js
326 | test262/test/staging/sm/regress/regress-577648-2.js
327 | test262/test/staging/sm/regress/regress-584355.js
328 | test262/test/staging/sm/regress/regress-586482-1.js
329 | test262/test/staging/sm/regress/regress-586482-2.js
330 | test262/test/staging/sm/regress/regress-586482-3.js
331 | test262/test/staging/sm/regress/regress-586482-4.js
332 | test262/test/staging/sm/regress/regress-699682.js
333 |
334 | # RegExp toSource not fully compliant
335 | test262/test/staging/sm/RegExp/toString.js
336 | test262/test/staging/sm/RegExp/source.js
337 | test262/test/staging/sm/RegExp/escape.js
338 | # source directives are not standard yet
339 | test262/test/staging/sm/syntax/syntax-parsed-arrow-then-directive.js
340 |
341 | [tests]
342 | # list test files or use config.testdir
343 |
--------------------------------------------------------------------------------
/test262_errors.txt:
--------------------------------------------------------------------------------
1 | test262/test/built-ins/Atomics/notify/retrieve-length-before-index-coercion-non-shared-detached.js:34: TypeError: ArrayBuffer is detached
2 | test262/test/built-ins/Atomics/notify/retrieve-length-before-index-coercion-non-shared-detached.js:34: strict mode: TypeError: ArrayBuffer is detached
3 | test262/test/language/module-code/top-level-await/module-graphs-does-not-hang.js:10: TypeError: $DONE() not called
4 | test262/test/staging/sm/Date/UTC-convert-all-arguments.js:75: Test262Error: index 1: expected 42, got Error: didn't throw Expected SameValue(«Error: didn't throw», «42») to be true
5 | test262/test/staging/sm/Date/constructor-convert-all-arguments.js:75: Test262Error: index undefined: expected 42, got Error: didn't throw Expected SameValue(«Error: didn't throw», «42») to be true
6 | test262/test/staging/sm/Date/non-iso.js:76: Test262Error: Expected SameValue(«NaN», «-40071559730000») to be true
7 | test262/test/staging/sm/Date/two-digit-years.js:76: Test262Error: Expected SameValue(«915177600000», «NaN») to be true
8 | test262/test/staging/sm/Function/arguments-parameter-shadowing.js:15: Test262Error: Expected SameValue(«true», «false») to be true
9 | test262/test/staging/sm/Function/constructor-binding.js:12: Test262Error: Expected SameValue(«"function"», «"undefined"») to be true
10 | test262/test/staging/sm/Function/function-bind.js:14: Test262Error: Conforms to NativeFunction Syntax: "function bound unbound() {\n [native code]\n}"
11 | test262/test/staging/sm/Function/function-name-for.js:12: Test262Error: Expected SameValue(«""», «"forInHead"») to be true
12 | test262/test/staging/sm/Function/function-toString-builtin.js:14: Test262Error: Expected match to '/^\s*function\s*(get|set)?\s*(\w+|(?:'[^']*')|(?:"[^"]*")|\d+|(?:\[[^\]]+\]))?\s*\(\s*\)\s*\{\s*\[native code\]\s*\}\s*$/', Actual value 'function bound fn() {
13 | [native code]
14 | }' Expected SameValue(«null», «null») to be false
15 | test262/test/staging/sm/Function/implicit-this-in-parameter-expression.js:13: Test262Error: Expected SameValue(«[object Object]», «undefined») to be true
16 | test262/test/staging/sm/Function/invalid-parameter-list.js:35: Error: Assertion failed: expected exception SyntaxError, no exception thrown
17 | test262/test/staging/sm/RegExp/constructor-ordering-2.js:15: Test262Error: Expected SameValue(«false», «true») to be true
18 | test262/test/staging/sm/RegExp/regress-613820-1.js:13: Test262Error: Expected SameValue(«"aaa"», «"aa"») to be true
19 | test262/test/staging/sm/RegExp/regress-613820-2.js:13: Test262Error: Expected SameValue(«"f"», «undefined») to be true
20 | test262/test/staging/sm/RegExp/regress-613820-3.js:13: Test262Error: Expected SameValue(«"aab"», «"aa"») to be true
21 | test262/test/staging/sm/TypedArray/constructor-buffer-sequence.js:73: Error: Assertion failed: expected exception ExpectedError, got Error: Poisoned Value
22 | test262/test/staging/sm/TypedArray/prototype-constructor-identity.js:17: Test262Error: Expected SameValue(«2», «6») to be true
23 | test262/test/staging/sm/TypedArray/set-detached-bigint.js:27: Error: Assertion failed: expected exception SyntaxError, got RangeError: invalid array length
24 | test262/test/staging/sm/TypedArray/set-detached.js:112: RangeError: invalid array length
25 | test262/test/staging/sm/TypedArray/sort_modifications.js:12: Test262Error: Int8Array at index 0 for size 4 Expected SameValue(«0», «1») to be true
26 | test262/test/staging/sm/TypedArray/subarray.js:15: Test262Error: Expected SameValue(«0», «1») to be true
27 | test262/test/staging/sm/async-functions/async-contains-unicode-escape.js:45: Error: Assertion failed: expected exception SyntaxError, no exception thrown
28 | test262/test/staging/sm/async-functions/await-error.js:12: Test262Error: Expected SameValue(«false», «true») to be true
29 | test262/test/staging/sm/async-functions/await-in-arrow-parameters.js:33: Error: Assertion failed: expected exception SyntaxError, no exception thrown - AsyncFunction:(a = (b = await/r/g) => {}) => {}
30 | test262/test/staging/sm/class/boundFunctionSubclassing.js:12: Test262Error: Expected SameValue(«false», «true») to be true
31 | test262/test/staging/sm/class/compPropNames.js:26: Error: Expected syntax error: ({[1, 2]: 3})
32 | test262/test/staging/sm/class/strictExecution.js:32: Error: Assertion failed: expected exception TypeError, no exception thrown
33 | test262/test/staging/sm/class/superPropOrdering.js:83: Error: Assertion failed: expected exception TypeError, no exception thrown
34 | test262/test/staging/sm/expressions/short-circuit-compound-assignment-const.js:97: TypeError: 'a' is read-only
35 | test262/test/staging/sm/expressions/short-circuit-compound-assignment-tdz.js:23: Error: Assertion failed: expected exception ReferenceError, got TypeError: 'a' is read-only
36 | test262/test/staging/sm/extensions/TypedArray-set-object-funky-length-detaches.js:55: RangeError: invalid array length
37 | test262/test/staging/sm/generators/syntax.js:30: Error: Assertion failed: expected SyntaxError, but no exception thrown - function* g() { (function* yield() {}); }
38 | test262/test/staging/sm/lexical-environment/block-scoped-functions-annex-b-arguments.js:14: Test262Error: Expected SameValue(«"object"», «"function"») to be true
39 | test262/test/staging/sm/lexical-environment/block-scoped-functions-annex-b-eval.js:12: Test262Error: Expected SameValue(«"outer-gouter-geval-gtruefalseq"», «"outer-geval-gwith-gtruefalseq"») to be true
40 | test262/test/staging/sm/lexical-environment/block-scoped-functions-annex-b-if.js:20: TypeError: not a function
41 | test262/test/staging/sm/lexical-environment/block-scoped-functions-annex-b-notapplicable.js:15: Test262Error: Expected SameValue(«function x() {2}», «function x() {1}») to be true
42 | test262/test/staging/sm/lexical-environment/block-scoped-functions-deprecated-redecl.js:23: Test262Error: Expected SameValue(«3», «4») to be true
43 | test262/test/staging/sm/lexical-environment/var-in-catch-body-annex-b-eval.js:17: Test262Error: Expected SameValue(«"g"», «"global-x"») to be true
44 | test262/test/staging/sm/object/defineProperties-order.js:14: Test262Error: Expected SameValue(«"ownKeys,getOwnPropertyDescriptor,getOwnPropertyDescriptor,get,get"», «"ownKeys,getOwnPropertyDescriptor,get,getOwnPropertyDescriptor,get"») to be true
45 | test262/test/staging/sm/regress/regress-602621.js:14: Test262Error: function sub-statement must override arguments Expected SameValue(«"function"», «"object"») to be true
46 | test262/test/staging/sm/regress/regress-1383630.js:30: Error: Assertion failed: expected exception TypeError, no exception thrown
47 | test262/test/staging/sm/statements/arrow-function-in-for-statement-head.js:15: Test262Error: expected syntax error, got Error: didn't throw Expected SameValue(«false», «true») to be true
48 | test262/test/staging/sm/statements/regress-642975.js:14: Test262Error: Expected SameValue(«undefined», «"y"») to be true
49 | test262/test/staging/sm/statements/try-completion.js:17: Test262Error: Expected SameValue(«"try"», «undefined») to be true
50 |
--------------------------------------------------------------------------------
/test262o_errors.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bellard/quickjs/638ec8ca5e1d4aed002a9fb3ef3358e2a6bc42ab/test262o_errors.txt
--------------------------------------------------------------------------------
/tests/assert.js:
--------------------------------------------------------------------------------
1 | export function assert(actual, expected, message) {
2 | if (arguments.length === 1)
3 | expected = true;
4 |
5 | if (typeof actual === typeof expected) {
6 | if (Object.is(actual, expected))
7 | return;
8 | if (typeof actual === 'object') {
9 | if (actual !== null && expected !== null
10 | && actual.constructor === expected.constructor
11 | && actual.toString() === expected.toString())
12 | return;
13 | }
14 | }
15 | throw Error("assertion failed: got |" + actual + "|" +
16 | ", expected |" + expected + "|" +
17 | (message ? " (" + message + ")" : ""));
18 | }
19 |
20 | export function assertThrows(err, func)
21 | {
22 | var ex;
23 | ex = false;
24 | try {
25 | func();
26 | } catch(e) {
27 | ex = true;
28 | assert(e instanceof err);
29 | }
30 | assert(ex, true, "exception expected");
31 | }
32 |
33 | export function assertArrayEquals(a, b)
34 | {
35 | if (!Array.isArray(a) || !Array.isArray(b))
36 | return assert(false);
37 |
38 | assert(a.length, b.length);
39 |
40 | a.forEach((value, idx) => {
41 | assert(b[idx], value);
42 | });
43 | }
44 |
--------------------------------------------------------------------------------
/tests/bjson.c:
--------------------------------------------------------------------------------
1 | /*
2 | * QuickJS: binary JSON module (test only)
3 | *
4 | * Copyright (c) 2017-2019 Fabrice Bellard
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 | #include "../quickjs-libc.h"
25 | #include "../cutils.h"
26 |
27 | static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val,
28 | int argc, JSValueConst *argv)
29 | {
30 | uint8_t *buf;
31 | uint64_t pos, len;
32 | JSValue obj;
33 | size_t size;
34 | int flags;
35 |
36 | if (JS_ToIndex(ctx, &pos, argv[1]))
37 | return JS_EXCEPTION;
38 | if (JS_ToIndex(ctx, &len, argv[2]))
39 | return JS_EXCEPTION;
40 | buf = JS_GetArrayBuffer(ctx, &size, argv[0]);
41 | if (!buf)
42 | return JS_EXCEPTION;
43 | if (pos + len > size)
44 | return JS_ThrowRangeError(ctx, "array buffer overflow");
45 | flags = 0;
46 | if (JS_ToBool(ctx, argv[3]))
47 | flags |= JS_READ_OBJ_REFERENCE;
48 | obj = JS_ReadObject(ctx, buf + pos, len, flags);
49 | return obj;
50 | }
51 |
52 | static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val,
53 | int argc, JSValueConst *argv)
54 | {
55 | size_t len;
56 | uint8_t *buf;
57 | JSValue array;
58 | int flags;
59 |
60 | flags = 0;
61 | if (JS_ToBool(ctx, argv[1]))
62 | flags |= JS_WRITE_OBJ_REFERENCE;
63 | buf = JS_WriteObject(ctx, &len, argv[0], flags);
64 | if (!buf)
65 | return JS_EXCEPTION;
66 | array = JS_NewArrayBufferCopy(ctx, buf, len);
67 | js_free(ctx, buf);
68 | return array;
69 | }
70 |
71 | static const JSCFunctionListEntry js_bjson_funcs[] = {
72 | JS_CFUNC_DEF("read", 4, js_bjson_read ),
73 | JS_CFUNC_DEF("write", 2, js_bjson_write ),
74 | };
75 |
76 | static int js_bjson_init(JSContext *ctx, JSModuleDef *m)
77 | {
78 | return JS_SetModuleExportList(ctx, m, js_bjson_funcs,
79 | countof(js_bjson_funcs));
80 | }
81 |
82 | #ifdef JS_SHARED_LIBRARY
83 | #define JS_INIT_MODULE js_init_module
84 | #else
85 | #define JS_INIT_MODULE js_init_module_bjson
86 | #endif
87 |
88 | JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)
89 | {
90 | JSModuleDef *m;
91 | m = JS_NewCModule(ctx, module_name, js_bjson_init);
92 | if (!m)
93 | return NULL;
94 | JS_AddModuleExportList(ctx, m, js_bjson_funcs, countof(js_bjson_funcs));
95 | return m;
96 | }
97 |
--------------------------------------------------------------------------------
/tests/fixture_cyclic_import.js:
--------------------------------------------------------------------------------
1 | import * as a from "./test_cyclic_import.js"
2 | export function f(x) { return 2 * a.g(x) }
3 |
--------------------------------------------------------------------------------
/tests/test262.patch:
--------------------------------------------------------------------------------
1 | diff --git a/harness/atomicsHelper.js b/harness/atomicsHelper.js
2 | index 9828b15..4a5919d 100644
3 | --- a/harness/atomicsHelper.js
4 | +++ b/harness/atomicsHelper.js
5 | @@ -272,10 +272,14 @@ $262.agent.waitUntil = function(typedArray, index, expected) {
6 | * }
7 | */
8 | $262.agent.timeouts = {
9 | - yield: 100,
10 | - small: 200,
11 | - long: 1000,
12 | - huge: 10000,
13 | +// yield: 100,
14 | +// small: 200,
15 | +// long: 1000,
16 | +// huge: 10000,
17 | + yield: 20,
18 | + small: 20,
19 | + long: 100,
20 | + huge: 1000,
21 | };
22 |
23 | /**
24 | diff --git a/harness/regExpUtils.js b/harness/regExpUtils.js
25 | index b397be0..c197ddc 100644
26 | --- a/harness/regExpUtils.js
27 | +++ b/harness/regExpUtils.js
28 | @@ -6,27 +6,30 @@ description: |
29 | defines: [buildString, testPropertyEscapes, testPropertyOfStrings, testExtendedCharacterClass, matchValidator]
30 | ---*/
31 |
32 | +if ($262 && typeof $262.codePointRange === "function") {
33 | + /* use C function to build the codePointRange (much faster with
34 | + slow JS engines) */
35 | + codePointRange = $262.codePointRange;
36 | +} else {
37 | + codePointRange = function codePointRange(start, end) {
38 | + const codePoints = [];
39 | + let length = 0;
40 | + for (codePoint = start; codePoint < end; codePoint++) {
41 | + codePoints[length++] = codePoint;
42 | + }
43 | + return String.fromCodePoint.apply(null, codePoints);
44 | + }
45 | +}
46 | +
47 | function buildString(args) {
48 | // Use member expressions rather than destructuring `args` for improved
49 | // compatibility with engines that only implement assignment patterns
50 | // partially or not at all.
51 | const loneCodePoints = args.loneCodePoints;
52 | const ranges = args.ranges;
53 | - const CHUNK_SIZE = 10000;
54 | let result = String.fromCodePoint.apply(null, loneCodePoints);
55 | - for (let i = 0; i < ranges.length; i++) {
56 | - let range = ranges[i];
57 | - let start = range[0];
58 | - let end = range[1];
59 | - let codePoints = [];
60 | - for (let length = 0, codePoint = start; codePoint <= end; codePoint++) {
61 | - codePoints[length++] = codePoint;
62 | - if (length === CHUNK_SIZE) {
63 | - result += String.fromCodePoint.apply(null, codePoints);
64 | - codePoints.length = length = 0;
65 | - }
66 | - }
67 | - result += String.fromCodePoint.apply(null, codePoints);
68 | + for (const [start, end] of ranges) {
69 | + result += codePointRange(start, end + 1);
70 | }
71 | return result;
72 | }
73 | diff --git a/harness/sm/non262.js b/harness/sm/non262.js
74 | index c1829e3..3a3ee27 100644
75 | --- a/harness/sm/non262.js
76 | +++ b/harness/sm/non262.js
77 | @@ -41,8 +41,6 @@ globalThis.createNewGlobal = function() {
78 | return $262.createRealm().global
79 | }
80 |
81 | -function print(...args) {
82 | -}
83 | function assertEq(...args) {
84 | assert.sameValue(...args)
85 | }
86 | @@ -71,4 +69,4 @@ if (globalThis.createExternalArrayBuffer === undefined) {
87 | if (globalThis.enableGeckoProfilingWithSlowAssertions === undefined) {
88 | globalThis.enableGeckoProfilingWithSlowAssertions = globalThis.enableGeckoProfiling =
89 | globalThis.disableGeckoProfiling = () => {}
90 | -}
91 | \ No newline at end of file
92 | +}
93 | diff --git a/test/staging/sm/extensions/regress-469625-01.js b/test/staging/sm/extensions/regress-469625-01.js
94 | index 5b62aeb..da07aae 100644
95 | --- a/test/staging/sm/extensions/regress-469625-01.js
96 | +++ b/test/staging/sm/extensions/regress-469625-01.js
97 | @@ -14,8 +14,7 @@ esid: pending
98 | //-----------------------------------------------------------------------------
99 | var BUGNUMBER = 469625;
100 | var summary = 'TM: Array prototype and expression closures';
101 | -var actual = '';
102 | -var expect = '';
103 | +var actual = null;
104 |
105 |
106 | //-----------------------------------------------------------------------------
107 | @@ -27,9 +26,6 @@ function test()
108 | printBugNumber(BUGNUMBER);
109 | printStatus (summary);
110 |
111 | - expect = 'TypeError: [].__proto__ is not a function';
112 | -
113 | -
114 | Array.prototype.__proto__ = function () { return 3; };
115 |
116 | try
117 | @@ -38,8 +34,10 @@ function test()
118 | }
119 | catch(ex)
120 | {
121 | - print(actual = ex + '');
122 | + print(ex + '');
123 | + actual = ex;
124 | }
125 |
126 | - assert.sameValue(expect, actual, summary);
127 | + assert.sameValue(actual instanceof TypeError, true);
128 | + assert.sameValue(actual.message.includes("not a function"), true);
129 | }
130 | diff --git a/test/staging/sm/misc/new-with-non-constructor.js b/test/staging/sm/misc/new-with-non-constructor.js
131 | index 18c2f0c..f9aa209 100644
132 | --- a/test/staging/sm/misc/new-with-non-constructor.js
133 | +++ b/test/staging/sm/misc/new-with-non-constructor.js
134 | @@ -16,7 +16,7 @@ function checkConstruct(thing) {
135 | new thing();
136 | assert.sameValue(0, 1, "not reached " + thing);
137 | } catch (e) {
138 | - assert.sameValue(e.message.includes(" is not a constructor") ||
139 | + assert.sameValue(e.message.includes("not a constructor") ||
140 | e.message === "Function.prototype.toString called on incompatible object", true);
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/tests/test_bigint.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | function assert(actual, expected, message) {
4 | if (arguments.length == 1)
5 | expected = true;
6 |
7 | if (actual === expected)
8 | return;
9 |
10 | if (actual !== null && expected !== null
11 | && typeof actual == 'object' && typeof expected == 'object'
12 | && actual.toString() === expected.toString())
13 | return;
14 |
15 | throw Error("assertion failed: got |" + actual + "|" +
16 | ", expected |" + expected + "|" +
17 | (message ? " (" + message + ")" : ""));
18 | }
19 |
20 | function assertThrows(err, func)
21 | {
22 | var ex;
23 | ex = false;
24 | try {
25 | func();
26 | } catch(e) {
27 | ex = true;
28 | assert(e instanceof err);
29 | }
30 | assert(ex, true, "exception expected");
31 | }
32 |
33 | // load more elaborate version of assert if available
34 | try { __loadScript("test_assert.js"); } catch(e) {}
35 |
36 | /*----------------*/
37 |
38 | function bigint_pow(a, n)
39 | {
40 | var r, i;
41 | r = 1n;
42 | for(i = 0n; i < n; i++)
43 | r *= a;
44 | return r;
45 | }
46 |
47 | /* a must be < b */
48 | function test_less(a, b)
49 | {
50 | assert(a < b);
51 | assert(!(b < a));
52 | assert(a <= b);
53 | assert(!(b <= a));
54 | assert(b > a);
55 | assert(!(a > b));
56 | assert(b >= a);
57 | assert(!(a >= b));
58 | assert(a != b);
59 | assert(!(a == b));
60 | }
61 |
62 | /* a must be numerically equal to b */
63 | function test_eq(a, b)
64 | {
65 | assert(a == b);
66 | assert(b == a);
67 | assert(!(a != b));
68 | assert(!(b != a));
69 | assert(a <= b);
70 | assert(b <= a);
71 | assert(!(a < b));
72 | assert(a >= b);
73 | assert(b >= a);
74 | assert(!(a > b));
75 | }
76 |
77 | function test_bigint1()
78 | {
79 | var a, r;
80 |
81 | test_less(2n, 3n);
82 | test_eq(3n, 3n);
83 |
84 | test_less(2, 3n);
85 | test_eq(3, 3n);
86 |
87 | test_less(2.1, 3n);
88 | test_eq(Math.sqrt(4), 2n);
89 |
90 | a = bigint_pow(3n, 100n);
91 | assert((a - 1n) != a);
92 | assert(a == 515377520732011331036461129765621272702107522001n);
93 | assert(a == 0x5a4653ca673768565b41f775d6947d55cf3813d1n);
94 |
95 | r = 1n << 31n;
96 | assert(r, 2147483648n, "1 << 31n === 2147483648n");
97 |
98 | r = 1n << 32n;
99 | assert(r, 4294967296n, "1 << 32n === 4294967296n");
100 | }
101 |
102 | function test_bigint2()
103 | {
104 | assert(BigInt(""), 0n);
105 | assert(BigInt(" 123"), 123n);
106 | assert(BigInt(" 123 "), 123n);
107 | assertThrows(SyntaxError, () => { BigInt("+") } );
108 | assertThrows(SyntaxError, () => { BigInt("-") } );
109 | assertThrows(SyntaxError, () => { BigInt("\x00a") } );
110 | assertThrows(SyntaxError, () => { BigInt(" 123 r") } );
111 | }
112 |
113 | function test_bigint3()
114 | {
115 | assert(Number(0xffffffffffffffffn), 18446744073709552000);
116 | assert(Number(-0xffffffffffffffffn), -18446744073709552000);
117 | assert(100000000000000000000n == 1e20, true);
118 | assert(100000000000000000001n == 1e20, false);
119 | assert((1n << 100n).toString(10), "1267650600228229401496703205376");
120 | assert((-1n << 100n).toString(36), "-3ewfdnca0n6ld1ggvfgg");
121 | assert((1n << 100n).toString(8), "2000000000000000000000000000000000");
122 |
123 | assert(0x5a4653ca673768565b41f775n << 78n, 8443945299673273647701379149826607537748959488376832n);
124 | assert(-0x5a4653ca673768565b41f775n << 78n, -8443945299673273647701379149826607537748959488376832n);
125 | assert(0x5a4653ca673768565b41f775n >> 78n, 92441n);
126 | assert(-0x5a4653ca673768565b41f775n >> 78n, -92442n);
127 |
128 | assert(~0x5a653ca6n, -1516584103n);
129 | assert(0x5a463ca6n | 0x67376856n, 2138537206n);
130 | assert(0x5a463ca6n & 0x67376856n, 1107699718n);
131 | assert(0x5a463ca6n ^ 0x67376856n, 1030837488n);
132 |
133 | assert(3213213213213213432453243n / 123434343439n, 26031760073331n);
134 | assert(-3213213213213213432453243n / 123434343439n, -26031760073331n);
135 | assert(-3213213213213213432453243n % -123434343439n, -26953727934n);
136 | assert(3213213213213213432453243n % 123434343439n, 26953727934n);
137 |
138 | assert((-2n) ** 127n, -170141183460469231731687303715884105728n);
139 | assert((2n) ** 127n, 170141183460469231731687303715884105728n);
140 | assert((-256n) ** 11n, -309485009821345068724781056n);
141 | assert((7n) ** 20n, 79792266297612001n);
142 | }
143 |
144 | /* pi computation */
145 |
146 | /* return floor(log2(a)) for a > 0 and 0 for a = 0 */
147 | function floor_log2(a)
148 | {
149 | var k_max, a1, k, i;
150 | k_max = 0n;
151 | while ((a >> (2n ** k_max)) != 0n) {
152 | k_max++;
153 | }
154 | k = 0n;
155 | a1 = a;
156 | for(i = k_max - 1n; i >= 0n; i--) {
157 | a1 = a >> (2n ** i);
158 | if (a1 != 0n) {
159 | a = a1;
160 | k |= (1n << i);
161 | }
162 | }
163 | return k;
164 | }
165 |
166 | /* return ceil(log2(a)) for a > 0 */
167 | function ceil_log2(a)
168 | {
169 | return floor_log2(a - 1n) + 1n;
170 | }
171 |
172 | /* return floor(sqrt(a)) (not efficient but simple) */
173 | function int_sqrt(a)
174 | {
175 | var l, u, s;
176 | if (a == 0n)
177 | return a;
178 | l = ceil_log2(a);
179 | u = 1n << ((l + 1n) / 2n);
180 | /* u >= floor(sqrt(a)) */
181 | for(;;) {
182 | s = u;
183 | u = ((a / s) + s) / 2n;
184 | if (u >= s)
185 | break;
186 | }
187 | return s;
188 | }
189 |
190 | /* return pi * 2**prec */
191 | function calc_pi(prec) {
192 | const CHUD_A = 13591409n;
193 | const CHUD_B = 545140134n;
194 | const CHUD_C = 640320n;
195 | const CHUD_C3 = 10939058860032000n; /* C^3/24 */
196 | const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */
197 |
198 | /* return [P, Q, G] */
199 | function chud_bs(a, b, need_G) {
200 | var c, P, Q, G, P1, Q1, G1, P2, Q2, G2;
201 | if (a == (b - 1n)) {
202 | G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n);
203 | P = G * (CHUD_B * b + CHUD_A);
204 | if (b & 1n)
205 | P = -P;
206 | Q = b * b * b * CHUD_C3;
207 | } else {
208 | c = (a + b) >> 1n;
209 | [P1, Q1, G1] = chud_bs(a, c, true);
210 | [P2, Q2, G2] = chud_bs(c, b, need_G);
211 | P = P1 * Q2 + P2 * G1;
212 | Q = Q1 * Q2;
213 | if (need_G)
214 | G = G1 * G2;
215 | else
216 | G = 0n;
217 | }
218 | return [P, Q, G];
219 | }
220 |
221 | var n, P, Q, G;
222 | /* number of serie terms */
223 | n = BigInt(Math.ceil(Number(prec) / CHUD_BITS_PER_TERM)) + 10n;
224 | [P, Q, G] = chud_bs(0n, n, false);
225 | Q = (CHUD_C / 12n) * (Q << prec) / (P + Q * CHUD_A);
226 | G = int_sqrt(CHUD_C << (2n * prec));
227 | return (Q * G) >> prec;
228 | }
229 |
230 | function compute_pi(n_digits) {
231 | var r, n_digits, n_bits, out;
232 | /* we add more bits to reduce the probability of bad rounding for
233 | the last digits */
234 | n_bits = BigInt(Math.ceil(n_digits * Math.log2(10))) + 32n;
235 | r = calc_pi(n_bits);
236 | r = ((10n ** BigInt(n_digits)) * r) >> n_bits;
237 | out = r.toString();
238 | return out[0] + "." + out.slice(1);
239 | }
240 |
241 | function test_pi()
242 | {
243 | assert(compute_pi(2000), "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960917363717872146844090122495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349042875546873115956286388235378759375195778185778053217122680661300192787661119590921642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151557485724245415069595082953311686172785588907509838175463746493931925506040092770167113900984882401285836160356370766010471018194295559619894676783744944825537977472684710404753464620804668425906949129331367702898915210475216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992458631503028618297455570674983850549458858692699569092721079750930295532116534498720275596023648066549911988183479775356636980742654252786255181841757467289097777279380008164706001614524919217321721477235014144197356854816136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179049460165346680498862723279178608578438382796797668145410095388378636095068006422512520511739298489608412848862694560424196528502221066118630674427862203919494504712371378696095636437191728746776465757396241389086583264599581339047802759009");
244 | }
245 |
246 | test_bigint1();
247 | test_bigint2();
248 | test_bigint3();
249 | test_pi();
250 |
--------------------------------------------------------------------------------
/tests/test_bjson.js:
--------------------------------------------------------------------------------
1 | import * as bjson from "./bjson.so";
2 |
3 | function assert(actual, expected, message) {
4 | if (arguments.length == 1)
5 | expected = true;
6 |
7 | if (actual === expected)
8 | return;
9 |
10 | if (actual !== null && expected !== null
11 | && typeof actual == 'object' && typeof expected == 'object'
12 | && actual.toString() === expected.toString())
13 | return;
14 |
15 | throw Error("assertion failed: got |" + actual + "|" +
16 | ", expected |" + expected + "|" +
17 | (message ? " (" + message + ")" : ""));
18 | }
19 |
20 | function toHex(a)
21 | {
22 | var i, s = "", tab, v;
23 | tab = new Uint8Array(a);
24 | for(i = 0; i < tab.length; i++) {
25 | v = tab[i].toString(16);
26 | if (v.length < 2)
27 | v = "0" + v;
28 | if (i !== 0)
29 | s += " ";
30 | s += v;
31 | }
32 | return s;
33 | }
34 |
35 | function isArrayLike(a)
36 | {
37 | return Array.isArray(a) ||
38 | (a instanceof Uint8ClampedArray) ||
39 | (a instanceof Uint8Array) ||
40 | (a instanceof Uint16Array) ||
41 | (a instanceof Uint32Array) ||
42 | (a instanceof Int8Array) ||
43 | (a instanceof Int16Array) ||
44 | (a instanceof Int32Array) ||
45 | (a instanceof Float16Array) ||
46 | (a instanceof Float32Array) ||
47 | (a instanceof Float64Array);
48 | }
49 |
50 | function toStr(a)
51 | {
52 | var s, i, props, prop;
53 |
54 | switch(typeof(a)) {
55 | case "object":
56 | if (a === null)
57 | return "null";
58 | if (a instanceof Date) {
59 | s = "Date(" + toStr(a.valueOf()) + ")";
60 | } else if (a instanceof Number) {
61 | s = "Number(" + toStr(a.valueOf()) + ")";
62 | } else if (a instanceof String) {
63 | s = "String(" + toStr(a.valueOf()) + ")";
64 | } else if (a instanceof Boolean) {
65 | s = "Boolean(" + toStr(a.valueOf()) + ")";
66 | } else if (isArrayLike(a)) {
67 | s = "[";
68 | for(i = 0; i < a.length; i++) {
69 | if (i != 0)
70 | s += ",";
71 | s += toStr(a[i]);
72 | }
73 | s += "]";
74 | } else {
75 | props = Object.keys(a);
76 | s = "{";
77 | for(i = 0; i < props.length; i++) {
78 | if (i != 0)
79 | s += ",";
80 | prop = props[i];
81 | s += prop + ":" + toStr(a[prop]);
82 | }
83 | s += "}";
84 | }
85 | return s;
86 | case "undefined":
87 | return "undefined";
88 | case "string":
89 | return a.__quote();
90 | case "number":
91 | if (a == 0 && 1 / a < 0)
92 | return "-0";
93 | else
94 | return a.toString();
95 | break;
96 | default:
97 | return a.toString();
98 | }
99 | }
100 |
101 | function bjson_test(a)
102 | {
103 | var buf, r, a_str, r_str;
104 | a_str = toStr(a);
105 | buf = bjson.write(a);
106 | if (0) {
107 | print(a_str, "->", toHex(buf));
108 | }
109 | r = bjson.read(buf, 0, buf.byteLength);
110 | r_str = toStr(r);
111 | if (a_str != r_str) {
112 | print(a_str);
113 | print(r_str);
114 | assert(false);
115 | }
116 | }
117 |
118 | /* test multiple references to an object including circular
119 | references */
120 | function bjson_test_reference()
121 | {
122 | var array, buf, i, n, array_buffer;
123 | n = 16;
124 | array = [];
125 | for(i = 0; i < n; i++)
126 | array[i] = {};
127 | array_buffer = new ArrayBuffer(n);
128 | for(i = 0; i < n; i++) {
129 | array[i].next = array[(i + 1) % n];
130 | array[i].idx = i;
131 | array[i].typed_array = new Uint8Array(array_buffer, i, 1);
132 | }
133 | buf = bjson.write(array, true);
134 |
135 | array = bjson.read(buf, 0, buf.byteLength, true);
136 |
137 | /* check the result */
138 | for(i = 0; i < n; i++) {
139 | assert(array[i].next, array[(i + 1) % n]);
140 | assert(array[i].idx, i);
141 | assert(array[i].typed_array.buffer, array_buffer);
142 | assert(array[i].typed_array.length, 1);
143 | assert(array[i].typed_array.byteOffset, i);
144 | }
145 | }
146 |
147 | function bjson_test_all()
148 | {
149 | var obj;
150 |
151 | bjson_test({x:1, y:2, if:3});
152 | bjson_test([1, 2, 3]);
153 | bjson_test([1.0, "aa", true, false, undefined, null, NaN, -Infinity, -0.0]);
154 | if (typeof BigInt !== "undefined") {
155 | bjson_test([BigInt("1"), -BigInt("0x123456789"),
156 | BigInt("0x123456789abcdef123456789abcdef")]);
157 | }
158 | bjson_test([new Date(1234), new String("abc"), new Number(-12.1), new Boolean(true)]);
159 |
160 | bjson_test(new Int32Array([123123, 222111, -32222]));
161 | bjson_test(new Float16Array([1024, 1024.5]));
162 | bjson_test(new Float64Array([123123, 222111.5]));
163 |
164 | /* tested with a circular reference */
165 | obj = {};
166 | obj.x = obj;
167 | try {
168 | bjson.write(obj);
169 | assert(false);
170 | } catch(e) {
171 | assert(e instanceof TypeError);
172 | }
173 |
174 | bjson_test_reference();
175 | }
176 |
177 | bjson_test_all();
178 |
--------------------------------------------------------------------------------
/tests/test_closure.js:
--------------------------------------------------------------------------------
1 | function assert(actual, expected, message) {
2 | if (arguments.length == 1)
3 | expected = true;
4 |
5 | if (actual === expected)
6 | return;
7 |
8 | if (actual !== null && expected !== null
9 | && typeof actual == 'object' && typeof expected == 'object'
10 | && actual.toString() === expected.toString())
11 | return;
12 |
13 | throw Error("assertion failed: got |" + actual + "|" +
14 | ", expected |" + expected + "|" +
15 | (message ? " (" + message + ")" : ""));
16 | }
17 |
18 | // load more elaborate version of assert if available
19 | try { __loadScript("test_assert.js"); } catch(e) {}
20 |
21 | /*----------------*/
22 |
23 | var log_str = "";
24 |
25 | function log(str)
26 | {
27 | log_str += str + ",";
28 | }
29 |
30 | function f(a, b, c)
31 | {
32 | var x = 10;
33 | log("a="+a);
34 | function g(d) {
35 | function h() {
36 | log("d=" + d);
37 | log("x=" + x);
38 | }
39 | log("b=" + b);
40 | log("c=" + c);
41 | h();
42 | }
43 | g(4);
44 | return g;
45 | }
46 |
47 | var g1 = f(1, 2, 3);
48 | g1(5);
49 |
50 | assert(log_str, "a=1,b=2,c=3,d=4,x=10,b=2,c=3,d=5,x=10,", "closure1");
51 |
52 | function test_closure1()
53 | {
54 | function f2()
55 | {
56 | var val = 1;
57 |
58 | function set(a) {
59 | val = a;
60 | }
61 | function get(a) {
62 | return val;
63 | }
64 | return { "set": set, "get": get };
65 | }
66 |
67 | var obj = f2();
68 | obj.set(10);
69 | var r;
70 | r = obj.get();
71 | assert(r, 10, "closure2");
72 | }
73 |
74 | function test_closure2()
75 | {
76 | var expr_func = function myfunc1(n) {
77 | function myfunc2(n) {
78 | return myfunc1(n - 1);
79 | }
80 | if (n == 0)
81 | return 0;
82 | else
83 | return myfunc2(n);
84 | };
85 | var r;
86 | r = expr_func(1);
87 | assert(r, 0, "expr_func");
88 | }
89 |
90 | function test_closure3()
91 | {
92 | function fib(n)
93 | {
94 | if (n <= 0)
95 | return 0;
96 | else if (n == 1)
97 | return 1;
98 | else
99 | return fib(n - 1) + fib(n - 2);
100 | }
101 |
102 | var fib_func = function fib1(n)
103 | {
104 | if (n <= 0)
105 | return 0;
106 | else if (n == 1)
107 | return 1;
108 | else
109 | return fib1(n - 1) + fib1(n - 2);
110 | };
111 |
112 | assert(fib(6), 8, "fib");
113 | assert(fib_func(6), 8, "fib_func");
114 | }
115 |
116 | function test_arrow_function()
117 | {
118 | "use strict";
119 |
120 | function f1() {
121 | return (() => arguments)();
122 | }
123 | function f2() {
124 | return (() => this)();
125 | }
126 | function f3() {
127 | return (() => eval("this"))();
128 | }
129 | function f4() {
130 | return (() => eval("new.target"))();
131 | }
132 | var a;
133 |
134 | a = f1(1, 2);
135 | assert(a.length, 2);
136 | assert(a[0] === 1 && a[1] === 2);
137 |
138 | assert(f2.call("this_val") === "this_val");
139 | assert(f3.call("this_val") === "this_val");
140 | assert(new f4() === f4);
141 |
142 | var o1 = { f() { return this; } };
143 | var o2 = { f() {
144 | return (() => eval("super.f()"))();
145 | } };
146 | o2.__proto__ = o1;
147 |
148 | assert(o2.f() === o2);
149 | }
150 |
151 | function test_with()
152 | {
153 | var o1 = { x: "o1", y: "o1" };
154 | var x = "local";
155 | eval('var z="var_obj";');
156 | assert(z === "var_obj");
157 | with (o1) {
158 | assert(x === "o1");
159 | assert(eval("x") === "o1");
160 | var f = function () {
161 | o2 = { x: "o2" };
162 | with (o2) {
163 | assert(x === "o2");
164 | assert(y === "o1");
165 | assert(z === "var_obj");
166 | assert(eval("x") === "o2");
167 | assert(eval("y") === "o1");
168 | assert(eval("z") === "var_obj");
169 | assert(eval('eval("x")') === "o2");
170 | }
171 | };
172 | f();
173 | }
174 | }
175 |
176 | function test_eval_closure()
177 | {
178 | var tab;
179 |
180 | tab = [];
181 | for(let i = 0; i < 3; i++) {
182 | eval("tab.push(function g1() { return i; })");
183 | }
184 | for(let i = 0; i < 3; i++) {
185 | assert(tab[i]() === i);
186 | }
187 |
188 | tab = [];
189 | for(let i = 0; i < 3; i++) {
190 | let f = function f() {
191 | eval("tab.push(function g2() { return i; })");
192 | };
193 | f();
194 | }
195 | for(let i = 0; i < 3; i++) {
196 | assert(tab[i]() === i);
197 | }
198 | }
199 |
200 | function test_eval_const()
201 | {
202 | const a = 1;
203 | var success = false;
204 | var f = function () {
205 | eval("a = 1");
206 | };
207 | try {
208 | f();
209 | } catch(e) {
210 | success = (e instanceof TypeError);
211 | }
212 | assert(success);
213 | }
214 |
215 | test_closure1();
216 | test_closure2();
217 | test_closure3();
218 | test_arrow_function();
219 | test_with();
220 | test_eval_closure();
221 | test_eval_const();
222 |
--------------------------------------------------------------------------------
/tests/test_cyclic_import.js:
--------------------------------------------------------------------------------
1 | /*---
2 | negative:
3 | phase: resolution
4 | type: SyntaxError
5 | ---*/
6 | // FIXME(bnoordhuis) shouldn't throw SyntaxError but that's still better
7 | // than segfaulting, see https://github.com/quickjs-ng/quickjs/issues/567
8 | import {assert} from "./assert.js"
9 | import {f} from "./fixture_cyclic_import.js"
10 | export {f}
11 | export function g(x) { return x + 1 }
12 | assert(f(1), 4)
13 |
--------------------------------------------------------------------------------
/tests/test_language.js:
--------------------------------------------------------------------------------
1 | function assert(actual, expected, message) {
2 | if (arguments.length == 1)
3 | expected = true;
4 |
5 | if (Object.is(actual, expected))
6 | return;
7 |
8 | if (actual !== null && expected !== null
9 | && typeof actual == 'object' && typeof expected == 'object'
10 | && actual.toString() === expected.toString())
11 | return;
12 |
13 | throw Error("assertion failed: got |" + actual + "|" +
14 | ", expected |" + expected + "|" +
15 | (message ? " (" + message + ")" : ""));
16 | }
17 |
18 | function assert_throws(expected_error, func)
19 | {
20 | var err = false;
21 | try {
22 | func();
23 | } catch(e) {
24 | err = true;
25 | if (!(e instanceof expected_error)) {
26 | throw Error("unexpected exception type");
27 | }
28 | }
29 | if (!err) {
30 | throw Error("expected exception");
31 | }
32 | }
33 |
34 | // load more elaborate version of assert if available
35 | try { __loadScript("test_assert.js"); } catch(e) {}
36 |
37 | /*----------------*/
38 |
39 | function test_op1()
40 | {
41 | var r, a;
42 | r = 1 + 2;
43 | assert(r, 3, "1 + 2 === 3");
44 |
45 | r = 1 - 2;
46 | assert(r, -1, "1 - 2 === -1");
47 |
48 | r = -1;
49 | assert(r, -1, "-1 === -1");
50 |
51 | r = +2;
52 | assert(r, 2, "+2 === 2");
53 |
54 | r = 2 * 3;
55 | assert(r, 6, "2 * 3 === 6");
56 |
57 | r = 4 / 2;
58 | assert(r, 2, "4 / 2 === 2");
59 |
60 | r = 4 % 3;
61 | assert(r, 1, "4 % 3 === 3");
62 |
63 | r = 4 << 2;
64 | assert(r, 16, "4 << 2 === 16");
65 |
66 | r = 1 << 0;
67 | assert(r, 1, "1 << 0 === 1");
68 |
69 | r = 1 << 31;
70 | assert(r, -2147483648, "1 << 31 === -2147483648");
71 |
72 | r = 1 << 32;
73 | assert(r, 1, "1 << 32 === 1");
74 |
75 | r = (1 << 31) < 0;
76 | assert(r, true, "(1 << 31) < 0 === true");
77 |
78 | r = -4 >> 1;
79 | assert(r, -2, "-4 >> 1 === -2");
80 |
81 | r = -4 >>> 1;
82 | assert(r, 0x7ffffffe, "-4 >>> 1 === 0x7ffffffe");
83 |
84 | r = 1 & 1;
85 | assert(r, 1, "1 & 1 === 1");
86 |
87 | r = 0 | 1;
88 | assert(r, 1, "0 | 1 === 1");
89 |
90 | r = 1 ^ 1;
91 | assert(r, 0, "1 ^ 1 === 0");
92 |
93 | r = ~1;
94 | assert(r, -2, "~1 === -2");
95 |
96 | r = !1;
97 | assert(r, false, "!1 === false");
98 |
99 | assert((1 < 2), true, "(1 < 2) === true");
100 |
101 | assert((2 > 1), true, "(2 > 1) === true");
102 |
103 | assert(('b' > 'a'), true, "('b' > 'a') === true");
104 |
105 | assert(2 ** 8, 256, "2 ** 8 === 256");
106 | }
107 |
108 | function test_cvt()
109 | {
110 | assert((NaN | 0) === 0);
111 | assert((Infinity | 0) === 0);
112 | assert(((-Infinity) | 0) === 0);
113 | assert(("12345" | 0) === 12345);
114 | assert(("0x12345" | 0) === 0x12345);
115 | assert(((4294967296 * 3 - 4) | 0) === -4);
116 |
117 | assert(("12345" >>> 0) === 12345);
118 | assert(("0x12345" >>> 0) === 0x12345);
119 | assert((NaN >>> 0) === 0);
120 | assert((Infinity >>> 0) === 0);
121 | assert(((-Infinity) >>> 0) === 0);
122 | assert(((4294967296 * 3 - 4) >>> 0) === (4294967296 - 4));
123 | assert((19686109595169230000).toString() === "19686109595169230000");
124 | }
125 |
126 | function test_eq()
127 | {
128 | assert(null == undefined);
129 | assert(undefined == null);
130 | assert(true == 1);
131 | assert(0 == false);
132 | assert("" == 0);
133 | assert("123" == 123);
134 | assert("122" != 123);
135 | assert((new Number(1)) == 1);
136 | assert(2 == (new Number(2)));
137 | assert((new String("abc")) == "abc");
138 | assert({} != "abc");
139 | }
140 |
141 | function test_inc_dec()
142 | {
143 | var a, r;
144 |
145 | a = 1;
146 | r = a++;
147 | assert(r === 1 && a === 2, true, "++");
148 |
149 | a = 1;
150 | r = ++a;
151 | assert(r === 2 && a === 2, true, "++");
152 |
153 | a = 1;
154 | r = a--;
155 | assert(r === 1 && a === 0, true, "--");
156 |
157 | a = 1;
158 | r = --a;
159 | assert(r === 0 && a === 0, true, "--");
160 |
161 | a = {x:true};
162 | a.x++;
163 | assert(a.x, 2, "++");
164 |
165 | a = {x:true};
166 | a.x--;
167 | assert(a.x, 0, "--");
168 |
169 | a = [true];
170 | a[0]++;
171 | assert(a[0], 2, "++");
172 |
173 | a = {x:true};
174 | r = a.x++;
175 | assert(r === 1 && a.x === 2, true, "++");
176 |
177 | a = {x:true};
178 | r = a.x--;
179 | assert(r === 1 && a.x === 0, true, "--");
180 |
181 | a = [true];
182 | r = a[0]++;
183 | assert(r === 1 && a[0] === 2, true, "++");
184 |
185 | a = [true];
186 | r = a[0]--;
187 | assert(r === 1 && a[0] === 0, true, "--");
188 | }
189 |
190 | function F(x)
191 | {
192 | this.x = x;
193 | }
194 |
195 | function test_op2()
196 | {
197 | var a, b;
198 | a = new Object;
199 | a.x = 1;
200 | assert(a.x, 1, "new");
201 | b = new F(2);
202 | assert(b.x, 2, "new");
203 |
204 | a = {x : 2};
205 | assert(("x" in a), true, "in");
206 | assert(("y" in a), false, "in");
207 |
208 | a = {};
209 | assert((a instanceof Object), true, "instanceof");
210 | assert((a instanceof String), false, "instanceof");
211 |
212 | assert((typeof 1), "number", "typeof");
213 | assert((typeof Object), "function", "typeof");
214 | assert((typeof null), "object", "typeof");
215 | assert((typeof unknown_var), "undefined", "typeof");
216 |
217 | a = {x: 1, if: 2, async: 3};
218 | assert(a.if === 2);
219 | assert(a.async === 3);
220 | }
221 |
222 | function test_delete()
223 | {
224 | var a, err;
225 |
226 | a = {x: 1, y: 1};
227 | assert((delete a.x), true, "delete");
228 | assert(("x" in a), false, "delete");
229 |
230 | /* the following are not tested by test262 */
231 | assert(delete "abc"[100], true);
232 |
233 | err = false;
234 | try {
235 | delete null.a;
236 | } catch(e) {
237 | err = (e instanceof TypeError);
238 | }
239 | assert(err, true, "delete");
240 |
241 | err = false;
242 | try {
243 | a = { f() { delete super.a; } };
244 | a.f();
245 | } catch(e) {
246 | err = (e instanceof ReferenceError);
247 | }
248 | assert(err, true, "delete");
249 | }
250 |
251 | function test_prototype()
252 | {
253 | var f = function f() { };
254 | assert(f.prototype.constructor, f, "prototype");
255 |
256 | var g = function g() { };
257 | /* QuickJS bug */
258 | Object.defineProperty(g, "prototype", { writable: false });
259 | assert(g.prototype.constructor, g, "prototype");
260 | }
261 |
262 | function test_arguments()
263 | {
264 | function f2() {
265 | assert(arguments.length, 2, "arguments");
266 | assert(arguments[0], 1, "arguments");
267 | assert(arguments[1], 3, "arguments");
268 | }
269 | f2(1, 3);
270 | }
271 |
272 | function test_class()
273 | {
274 | var o;
275 | class C {
276 | constructor() {
277 | this.x = 10;
278 | }
279 | f() {
280 | return 1;
281 | }
282 | static F() {
283 | return -1;
284 | }
285 | get y() {
286 | return 12;
287 | }
288 | };
289 | class D extends C {
290 | constructor() {
291 | super();
292 | this.z = 20;
293 | }
294 | g() {
295 | return 2;
296 | }
297 | static G() {
298 | return -2;
299 | }
300 | h() {
301 | return super.f();
302 | }
303 | static H() {
304 | return super["F"]();
305 | }
306 | }
307 |
308 | assert(C.F() === -1);
309 | assert(Object.getOwnPropertyDescriptor(C.prototype, "y").get.name === "get y");
310 |
311 | o = new C();
312 | assert(o.f() === 1);
313 | assert(o.x === 10);
314 |
315 | assert(D.F() === -1);
316 | assert(D.G() === -2);
317 | assert(D.H() === -1);
318 |
319 | o = new D();
320 | assert(o.f() === 1);
321 | assert(o.g() === 2);
322 | assert(o.x === 10);
323 | assert(o.z === 20);
324 | assert(o.h() === 1);
325 |
326 | /* test class name scope */
327 | var E1 = class E { static F() { return E; } };
328 | assert(E1 === E1.F());
329 |
330 | class S {
331 | static x = 42;
332 | static y = S.x;
333 | static z = this.x;
334 | }
335 | assert(S.x === 42);
336 | assert(S.y === 42);
337 | assert(S.z === 42);
338 |
339 | class P {
340 | get = () => "123";
341 | static() { return 42; }
342 | }
343 | assert(new P().get() === "123");
344 | assert(new P().static() === 42);
345 | };
346 |
347 | function test_template()
348 | {
349 | var a, b;
350 | b = 123;
351 | a = `abc${b}d`;
352 | assert(a, "abc123d");
353 |
354 | a = String.raw `abc${b}d`;
355 | assert(a, "abc123d");
356 |
357 | a = "aaa";
358 | b = "bbb";
359 | assert(`aaa${a, b}ccc`, "aaabbbccc");
360 | }
361 |
362 | function test_template_skip()
363 | {
364 | var a = "Bar";
365 | var { b = `${a + `a${a}` }baz` } = {};
366 | assert(b, "BaraBarbaz");
367 | }
368 |
369 | function test_object_literal()
370 | {
371 | var x = 0, get = 1, set = 2; async = 3;
372 | a = { get: 2, set: 3, async: 4, get a(){ return this.get} };
373 | assert(JSON.stringify(a), '{"get":2,"set":3,"async":4,"a":2}');
374 | assert(a.a === 2);
375 |
376 | a = { x, get, set, async };
377 | assert(JSON.stringify(a), '{"x":0,"get":1,"set":2,"async":3}');
378 | }
379 |
380 | function test_regexp_skip()
381 | {
382 | var a, b;
383 | [a, b = /abc\(/] = [1];
384 | assert(a === 1);
385 |
386 | [a, b =/abc\(/] = [2];
387 | assert(a === 2);
388 | }
389 |
390 | function test_labels()
391 | {
392 | do x: { break x; } while(0);
393 | if (1)
394 | x: { break x; }
395 | else
396 | x: { break x; }
397 | with ({}) x: { break x; };
398 | while (0) x: { break x; };
399 | }
400 |
401 | function test_labels2()
402 | {
403 | while (1) label: break
404 | var i = 0
405 | while (i < 3) label: {
406 | if (i > 0)
407 | break
408 | i++
409 | }
410 | assert(i, 1)
411 | for (;;) label: break
412 | for (i = 0; i < 3; i++) label: {
413 | if (i > 0)
414 | break
415 | }
416 | assert(i, 1)
417 | }
418 |
419 | function test_destructuring()
420 | {
421 | function * g () { return 0; };
422 | var [x] = g();
423 | assert(x, void 0);
424 | }
425 |
426 | function test_spread()
427 | {
428 | var x;
429 | x = [1, 2, ...[3, 4]];
430 | assert(x.toString(), "1,2,3,4");
431 |
432 | x = [ ...[ , ] ];
433 | assert(Object.getOwnPropertyNames(x).toString(), "0,length");
434 | }
435 |
436 | function test_function_length()
437 | {
438 | assert( ((a, b = 1, c) => {}).length, 1);
439 | assert( (([a,b]) => {}).length, 1);
440 | assert( (({a,b}) => {}).length, 1);
441 | assert( ((c, [a,b] = 1, d) => {}).length, 1);
442 | }
443 |
444 | function test_argument_scope()
445 | {
446 | var f;
447 | var c = "global";
448 |
449 | (function() {
450 | "use strict";
451 | // XXX: node only throws in strict mode
452 | f = function(a = eval("var arguments")) {};
453 | assert_throws(SyntaxError, f);
454 | })();
455 |
456 | f = function(a = eval("1"), b = arguments[0]) { return b; };
457 | assert(f(12), 12);
458 |
459 | f = function(a, b = arguments[0]) { return b; };
460 | assert(f(12), 12);
461 |
462 | f = function(a, b = () => arguments) { return b; };
463 | assert(f(12)()[0], 12);
464 |
465 | f = function(a = eval("1"), b = () => arguments) { return b; };
466 | assert(f(12)()[0], 12);
467 |
468 | (function() {
469 | "use strict";
470 | f = function(a = this) { return a; };
471 | assert(f.call(123), 123);
472 |
473 | f = function f(a = f) { return a; };
474 | assert(f(), f);
475 |
476 | f = function f(a = eval("f")) { return a; };
477 | assert(f(), f);
478 | })();
479 |
480 | f = (a = eval("var c = 1"), probe = () => c) => {
481 | var c = 2;
482 | assert(c, 2);
483 | assert(probe(), 1);
484 | }
485 | f();
486 |
487 | f = (a = eval("var arguments = 1"), probe = () => arguments) => {
488 | var arguments = 2;
489 | assert(arguments, 2);
490 | assert(probe(), 1);
491 | }
492 | f();
493 |
494 | f = function f(a = eval("var c = 1"), b = c, probe = () => c) {
495 | assert(b, 1);
496 | assert(c, 1);
497 | assert(probe(), 1)
498 | }
499 | f();
500 |
501 | assert(c, "global");
502 | f = function f(a, b = c, probe = () => c) {
503 | eval("var c = 1");
504 | assert(c, 1);
505 | assert(b, "global");
506 | assert(probe(), "global")
507 | }
508 | f();
509 | assert(c, "global");
510 |
511 | f = function f(a = eval("var c = 1"), probe = (d = eval("c")) => d) {
512 | assert(probe(), 1)
513 | }
514 | f();
515 | }
516 |
517 | function test_function_expr_name()
518 | {
519 | var f;
520 |
521 | /* non strict mode test : assignment to the function name silently
522 | fails */
523 |
524 | f = function myfunc() {
525 | myfunc = 1;
526 | return myfunc;
527 | };
528 | assert(f(), f);
529 |
530 | f = function myfunc() {
531 | myfunc = 1;
532 | (() => {
533 | myfunc = 1;
534 | })();
535 | return myfunc;
536 | };
537 | assert(f(), f);
538 |
539 | f = function myfunc() {
540 | eval("myfunc = 1");
541 | return myfunc;
542 | };
543 | assert(f(), f);
544 |
545 | /* strict mode test : assignment to the function name raises a
546 | TypeError exception */
547 |
548 | f = function myfunc() {
549 | "use strict";
550 | myfunc = 1;
551 | };
552 | assert_throws(TypeError, f);
553 |
554 | f = function myfunc() {
555 | "use strict";
556 | (() => {
557 | myfunc = 1;
558 | })();
559 | };
560 | assert_throws(TypeError, f);
561 |
562 | f = function myfunc() {
563 | "use strict";
564 | eval("myfunc = 1");
565 | };
566 | assert_throws(TypeError, f);
567 | }
568 |
569 | function test_parse_semicolon()
570 | {
571 | /* 'yield' or 'await' may not be considered as a token if the
572 | previous ';' is missing */
573 | function *f()
574 | {
575 | function func() {
576 | }
577 | yield 1;
578 | var h = x => x + 1
579 | yield 2;
580 | }
581 | async function g()
582 | {
583 | function func() {
584 | }
585 | await 1;
586 | var h = x => x + 1
587 | await 2;
588 | }
589 | }
590 |
591 | function test_parse_arrow_function()
592 | {
593 | assert(typeof eval("() => {}\n() => {}"), "function");
594 | assert(eval("() => {}\n+1"), 1);
595 | assert(typeof eval("x => {}\n() => {}"), "function");
596 | assert(typeof eval("async () => {}\n() => {}"), "function");
597 | assert(typeof eval("async x => {}\n() => {}"), "function");
598 | }
599 |
600 | /* optional chaining tests not present in test262 */
601 | function test_optional_chaining()
602 | {
603 | var a, z;
604 | z = null;
605 | a = { b: { c: 2 } };
606 | assert(delete z?.b.c, true);
607 | assert(delete a?.b.c, true);
608 | assert(JSON.stringify(a), '{"b":{}}', "optional chaining delete");
609 |
610 | a = { b: { c: 2 } };
611 | assert(delete z?.b["c"], true);
612 | assert(delete a?.b["c"], true);
613 | assert(JSON.stringify(a), '{"b":{}}');
614 |
615 | a = {
616 | b() { return this._b; },
617 | _b: { c: 42 }
618 | };
619 |
620 | assert((a?.b)().c, 42);
621 |
622 | assert((a?.["b"])().c, 42);
623 | }
624 |
625 | function test_unicode_ident()
626 | {
627 | var õ = 3;
628 | assert(typeof õ, "undefined");
629 | }
630 |
631 | test_op1();
632 | test_cvt();
633 | test_eq();
634 | test_inc_dec();
635 | test_op2();
636 | test_delete();
637 | test_prototype();
638 | test_arguments();
639 | test_class();
640 | test_template();
641 | test_template_skip();
642 | test_object_literal();
643 | test_regexp_skip();
644 | test_labels();
645 | test_labels2();
646 | test_destructuring();
647 | test_spread();
648 | test_function_length();
649 | test_argument_scope();
650 | test_function_expr_name();
651 | test_parse_semicolon();
652 | test_optional_chaining();
653 | test_parse_arrow_function();
654 | test_unicode_ident();
655 |
--------------------------------------------------------------------------------
/tests/test_loop.js:
--------------------------------------------------------------------------------
1 | function assert(actual, expected, message) {
2 | if (arguments.length == 1)
3 | expected = true;
4 |
5 | if (actual === expected)
6 | return;
7 |
8 | if (actual !== null && expected !== null
9 | && typeof actual == 'object' && typeof expected == 'object'
10 | && actual.toString() === expected.toString())
11 | return;
12 |
13 | throw Error("assertion failed: got |" + actual + "|" +
14 | ", expected |" + expected + "|" +
15 | (message ? " (" + message + ")" : ""));
16 | }
17 |
18 | // load more elaborate version of assert if available
19 | try { __loadScript("test_assert.js"); } catch(e) {}
20 |
21 | /*----------------*/
22 |
23 | function test_while()
24 | {
25 | var i, c;
26 | i = 0;
27 | c = 0;
28 | while (i < 3) {
29 | c++;
30 | i++;
31 | }
32 | assert(c === 3);
33 | }
34 |
35 | function test_while_break()
36 | {
37 | var i, c;
38 | i = 0;
39 | c = 0;
40 | while (i < 3) {
41 | c++;
42 | if (i == 1)
43 | break;
44 | i++;
45 | }
46 | assert(c === 2 && i === 1);
47 | }
48 |
49 | function test_do_while()
50 | {
51 | var i, c;
52 | i = 0;
53 | c = 0;
54 | do {
55 | c++;
56 | i++;
57 | } while (i < 3);
58 | assert(c === 3 && i === 3);
59 | }
60 |
61 | function test_for()
62 | {
63 | var i, c;
64 | c = 0;
65 | for(i = 0; i < 3; i++) {
66 | c++;
67 | }
68 | assert(c === 3 && i === 3);
69 |
70 | c = 0;
71 | for(var j = 0; j < 3; j++) {
72 | c++;
73 | }
74 | assert(c === 3 && j === 3);
75 | }
76 |
77 | function test_for_in()
78 | {
79 | var i, tab, a, b;
80 |
81 | tab = [];
82 | for(i in {x:1, y: 2}) {
83 | tab.push(i);
84 | }
85 | assert(tab.toString(), "x,y", "for_in");
86 |
87 | /* prototype chain test */
88 | a = {x:2, y: 2, "1": 3};
89 | b = {"4" : 3 };
90 | Object.setPrototypeOf(a, b);
91 | tab = [];
92 | for(i in a) {
93 | tab.push(i);
94 | }
95 | assert(tab.toString(), "1,x,y,4", "for_in");
96 |
97 | /* non enumerable properties hide enumerables ones in the
98 | prototype chain */
99 | a = {y: 2, "1": 3};
100 | Object.defineProperty(a, "x", { value: 1 });
101 | b = {"x" : 3 };
102 | Object.setPrototypeOf(a, b);
103 | tab = [];
104 | for(i in a) {
105 | tab.push(i);
106 | }
107 | assert(tab.toString(), "1,y", "for_in");
108 |
109 | /* array optimization */
110 | a = [];
111 | for(i = 0; i < 10; i++)
112 | a.push(i);
113 | tab = [];
114 | for(i in a) {
115 | tab.push(i);
116 | }
117 | assert(tab.toString(), "0,1,2,3,4,5,6,7,8,9", "for_in");
118 |
119 | /* iterate with a field */
120 | a={x:0};
121 | tab = [];
122 | for(a.x in {x:1, y: 2}) {
123 | tab.push(a.x);
124 | }
125 | assert(tab.toString(), "x,y", "for_in");
126 |
127 | /* iterate with a variable field */
128 | a=[0];
129 | tab = [];
130 | for(a[0] in {x:1, y: 2}) {
131 | tab.push(a[0]);
132 | }
133 | assert(tab.toString(), "x,y", "for_in");
134 |
135 | /* variable definition in the for in */
136 | tab = [];
137 | for(var j in {x:1, y: 2}) {
138 | tab.push(j);
139 | }
140 | assert(tab.toString(), "x,y", "for_in");
141 |
142 | /* variable assigment in the for in */
143 | tab = [];
144 | for(var k = 2 in {x:1, y: 2}) {
145 | tab.push(k);
146 | }
147 | assert(tab.toString(), "x,y", "for_in");
148 | }
149 |
150 | function test_for_in2()
151 | {
152 | var i, tab;
153 | tab = [];
154 | for(i in {x:1, y: 2, z:3}) {
155 | if (i === "y")
156 | continue;
157 | tab.push(i);
158 | }
159 | assert(tab.toString() == "x,z");
160 |
161 | tab = [];
162 | for(i in {x:1, y: 2, z:3}) {
163 | if (i === "z")
164 | break;
165 | tab.push(i);
166 | }
167 | assert(tab.toString() == "x,y");
168 | }
169 |
170 | function test_for_in_proxy() {
171 | let removed_key = "";
172 | let target = {}
173 | let proxy = new Proxy(target, {
174 | ownKeys: function() {
175 | return ["a", "b", "c"];
176 | },
177 | getOwnPropertyDescriptor: function(target, key) {
178 | if (removed_key != "" && key == removed_key)
179 | return undefined;
180 | else
181 | return { enumerable: true, configurable: true, value: this[key] };
182 | }
183 | });
184 | let str = "";
185 | for(let o in proxy) {
186 | str += " " + o;
187 | if (o == "a")
188 | removed_key = "b";
189 | }
190 | assert(str == " a c");
191 | }
192 |
193 | function test_for_break()
194 | {
195 | var i, c;
196 | c = 0;
197 | L1: for(i = 0; i < 3; i++) {
198 | c++;
199 | if (i == 0)
200 | continue;
201 | while (1) {
202 | break L1;
203 | }
204 | }
205 | assert(c === 2 && i === 1);
206 | }
207 |
208 | function test_switch1()
209 | {
210 | var i, a, s;
211 | s = "";
212 | for(i = 0; i < 3; i++) {
213 | a = "?";
214 | switch(i) {
215 | case 0:
216 | a = "a";
217 | break;
218 | case 1:
219 | a = "b";
220 | break;
221 | default:
222 | a = "c";
223 | break;
224 | }
225 | s += a;
226 | }
227 | assert(s === "abc" && i === 3);
228 | }
229 |
230 | function test_switch2()
231 | {
232 | var i, a, s;
233 | s = "";
234 | for(i = 0; i < 4; i++) {
235 | a = "?";
236 | switch(i) {
237 | case 0:
238 | a = "a";
239 | break;
240 | case 1:
241 | a = "b";
242 | break;
243 | case 2:
244 | continue;
245 | default:
246 | a = "" + i;
247 | break;
248 | }
249 | s += a;
250 | }
251 | assert(s === "ab3" && i === 4);
252 | }
253 |
254 | function test_try_catch1()
255 | {
256 | try {
257 | throw "hello";
258 | } catch (e) {
259 | assert(e, "hello", "catch");
260 | return;
261 | }
262 | assert(false, "catch");
263 | }
264 |
265 | function test_try_catch2()
266 | {
267 | var a;
268 | try {
269 | a = 1;
270 | } catch (e) {
271 | a = 2;
272 | }
273 | assert(a, 1, "catch");
274 | }
275 |
276 | function test_try_catch3()
277 | {
278 | var s;
279 | s = "";
280 | try {
281 | s += "t";
282 | } catch (e) {
283 | s += "c";
284 | } finally {
285 | s += "f";
286 | }
287 | assert(s, "tf", "catch");
288 | }
289 |
290 | function test_try_catch4()
291 | {
292 | var s;
293 | s = "";
294 | try {
295 | s += "t";
296 | throw "c";
297 | } catch (e) {
298 | s += e;
299 | } finally {
300 | s += "f";
301 | }
302 | assert(s, "tcf", "catch");
303 | }
304 |
305 | function test_try_catch5()
306 | {
307 | var s;
308 | s = "";
309 | for(;;) {
310 | try {
311 | s += "t";
312 | break;
313 | s += "b";
314 | } finally {
315 | s += "f";
316 | }
317 | }
318 | assert(s, "tf", "catch");
319 | }
320 |
321 | function test_try_catch6()
322 | {
323 | function f() {
324 | try {
325 | s += 't';
326 | return 1;
327 | } finally {
328 | s += "f";
329 | }
330 | }
331 | var s = "";
332 | assert(f() === 1);
333 | assert(s, "tf", "catch6");
334 | }
335 |
336 | function test_try_catch7()
337 | {
338 | var s;
339 | s = "";
340 |
341 | try {
342 | try {
343 | s += "t";
344 | throw "a";
345 | } finally {
346 | s += "f";
347 | }
348 | } catch(e) {
349 | s += e;
350 | } finally {
351 | s += "g";
352 | }
353 | assert(s, "tfag", "catch");
354 | }
355 |
356 | function test_try_catch8()
357 | {
358 | var i, s;
359 |
360 | s = "";
361 | for(var i in {x:1, y:2}) {
362 | try {
363 | s += i;
364 | throw "a";
365 | } catch (e) {
366 | s += e;
367 | } finally {
368 | s += "f";
369 | }
370 | }
371 | assert(s === "xafyaf");
372 | }
373 |
374 | function test_cyclic_labels()
375 | {
376 | /* just check that it compiles without a crash */
377 | for (;;) {
378 | l: break l;
379 | l: break l;
380 | l: break l;
381 | }
382 | }
383 |
384 | test_while();
385 | test_while_break();
386 | test_do_while();
387 | test_for();
388 | test_for_break();
389 | test_switch1();
390 | test_switch2();
391 | test_for_in();
392 | test_for_in2();
393 | test_for_in_proxy();
394 |
395 | test_try_catch1();
396 | test_try_catch2();
397 | test_try_catch3();
398 | test_try_catch4();
399 | test_try_catch5();
400 | test_try_catch6();
401 | test_try_catch7();
402 | test_try_catch8();
403 |
--------------------------------------------------------------------------------
/tests/test_std.js:
--------------------------------------------------------------------------------
1 | #! (shebang test)
2 | import * as std from "std";
3 | import * as os from "os";
4 |
5 | function assert(actual, expected, message) {
6 | if (arguments.length == 1)
7 | expected = true;
8 |
9 | if (Object.is(actual, expected))
10 | return;
11 |
12 | if (actual !== null && expected !== null
13 | && typeof actual == 'object' && typeof expected == 'object'
14 | && actual.toString() === expected.toString())
15 | return;
16 |
17 | throw Error("assertion failed: got |" + actual + "|" +
18 | ", expected |" + expected + "|" +
19 | (message ? " (" + message + ")" : ""));
20 | }
21 |
22 | // load more elaborate version of assert if available
23 | try { std.loadScript("test_assert.js"); } catch(e) {}
24 |
25 | /*----------------*/
26 |
27 | function test_printf()
28 | {
29 | assert(std.sprintf("a=%d s=%s", 123, "abc"), "a=123 s=abc");
30 | assert(std.sprintf("%010d", 123), "0000000123");
31 | assert(std.sprintf("%x", -2), "fffffffe");
32 | assert(std.sprintf("%lx", -2), "fffffffffffffffe");
33 | assert(std.sprintf("%10.1f", 2.1), " 2.1");
34 | assert(std.sprintf("%*.*f", 10, 2, -2.13), " -2.13");
35 | assert(std.sprintf("%#lx", 0x7fffffffffffffffn), "0x7fffffffffffffff");
36 | }
37 |
38 | function test_file1()
39 | {
40 | var f, len, str, size, buf, ret, i, str1;
41 |
42 | f = std.tmpfile();
43 | str = "hello world\n";
44 | f.puts(str);
45 |
46 | f.seek(0, std.SEEK_SET);
47 | str1 = f.readAsString();
48 | assert(str1 === str);
49 |
50 | f.seek(0, std.SEEK_END);
51 | size = f.tell();
52 | assert(size === str.length);
53 |
54 | f.seek(0, std.SEEK_SET);
55 |
56 | buf = new Uint8Array(size);
57 | ret = f.read(buf.buffer, 0, size);
58 | assert(ret === size);
59 | for(i = 0; i < size; i++)
60 | assert(buf[i] === str.charCodeAt(i));
61 |
62 | f.close();
63 | }
64 |
65 | function test_file2()
66 | {
67 | var f, str, i, size;
68 | f = std.tmpfile();
69 | str = "hello world\n";
70 | size = str.length;
71 | for(i = 0; i < size; i++)
72 | f.putByte(str.charCodeAt(i));
73 | f.seek(0, std.SEEK_SET);
74 | for(i = 0; i < size; i++) {
75 | assert(str.charCodeAt(i) === f.getByte());
76 | }
77 | assert(f.getByte() === -1);
78 | f.close();
79 | }
80 |
81 | function test_getline()
82 | {
83 | var f, line, line_count, lines, i;
84 |
85 | lines = ["hello world", "line 1", "line 2" ];
86 | f = std.tmpfile();
87 | for(i = 0; i < lines.length; i++) {
88 | f.puts(lines[i], "\n");
89 | }
90 |
91 | f.seek(0, std.SEEK_SET);
92 | assert(!f.eof());
93 | line_count = 0;
94 | for(;;) {
95 | line = f.getline();
96 | if (line === null)
97 | break;
98 | assert(line == lines[line_count]);
99 | line_count++;
100 | }
101 | assert(f.eof());
102 | assert(line_count === lines.length);
103 |
104 | f.close();
105 | }
106 |
107 | function test_popen()
108 | {
109 | var str, f, fname = "tmp_file.txt";
110 | var content = "hello world";
111 |
112 | f = std.open(fname, "w");
113 | f.puts(content);
114 | f.close();
115 |
116 | /* test loadFile */
117 | assert(std.loadFile(fname), content);
118 |
119 | /* execute the 'cat' shell command */
120 | f = std.popen("cat " + fname, "r");
121 | str = f.readAsString();
122 | f.close();
123 |
124 | assert(str, content);
125 |
126 | os.remove(fname);
127 | }
128 |
129 | function test_ext_json()
130 | {
131 | var expected, input, obj;
132 | expected = '{"x":false,"y":true,"z2":null,"a":[1,8,160],"b":"abc\\u000bd","s":"str"}';
133 | input = `{ "x":false, /*comments are allowed */
134 | "y":true, // also a comment
135 | z2:null, // unquoted property names
136 | "a":[+1,0o10,0xa0,], // plus prefix, octal, hexadecimal
137 | "b": "ab\
138 | c\\vd", // multi-line strings, '\v' escape
139 | "s":'str',} // trailing comma in objects and arrays, single quoted string
140 | `;
141 | obj = std.parseExtJSON(input);
142 | assert(JSON.stringify(obj), expected);
143 |
144 | obj = std.parseExtJSON('[Infinity, +Infinity, -Infinity, NaN, +NaN, -NaN, .1, -.2]');
145 | assert(obj[0], Infinity);
146 | assert(obj[1], Infinity);
147 | assert(obj[2], -Infinity);
148 | assert(obj[3], NaN);
149 | assert(obj[4], NaN);
150 | assert(obj[5], NaN);
151 | assert(obj[6], 0.1);
152 | assert(obj[7], -0.2);
153 | }
154 |
155 | function test_os()
156 | {
157 | var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path;
158 |
159 | const stdinIsTTY = !os.exec(["/bin/sh", "-c", "test -t 0"], { usePath: false });
160 |
161 | assert(os.isatty(0), stdinIsTTY, `isatty(STDIN)`);
162 |
163 | fdir = "test_tmp_dir";
164 | fname = "tmp_file.txt";
165 | fpath = fdir + "/" + fname;
166 | link_path = fdir + "/test_link";
167 |
168 | os.remove(link_path);
169 | os.remove(fpath);
170 | os.remove(fdir);
171 |
172 | err = os.mkdir(fdir, 0o755);
173 | assert(err === 0);
174 |
175 | fd = os.open(fpath, os.O_RDWR | os.O_CREAT | os.O_TRUNC);
176 | assert(fd >= 0);
177 |
178 | buf = new Uint8Array(10);
179 | for(i = 0; i < buf.length; i++)
180 | buf[i] = i;
181 | assert(os.write(fd, buf.buffer, 0, buf.length) === buf.length);
182 |
183 | assert(os.seek(fd, 0, std.SEEK_SET) === 0);
184 | buf2 = new Uint8Array(buf.length);
185 | assert(os.read(fd, buf2.buffer, 0, buf2.length) === buf2.length);
186 |
187 | for(i = 0; i < buf.length; i++)
188 | assert(buf[i] == buf2[i]);
189 |
190 | if (typeof BigInt !== "undefined") {
191 | assert(os.seek(fd, BigInt(6), std.SEEK_SET), BigInt(6));
192 | assert(os.read(fd, buf2.buffer, 0, 1) === 1);
193 | assert(buf[6] == buf2[0]);
194 | }
195 |
196 | assert(os.close(fd) === 0);
197 |
198 | [files, err] = os.readdir(fdir);
199 | assert(err, 0);
200 | assert(files.indexOf(fname) >= 0);
201 |
202 | fdate = 10000;
203 |
204 | err = os.utimes(fpath, fdate, fdate);
205 | assert(err, 0);
206 |
207 | [st, err] = os.stat(fpath);
208 | assert(err, 0);
209 | assert(st.mode & os.S_IFMT, os.S_IFREG);
210 | assert(st.mtime, fdate);
211 |
212 | err = os.symlink(fname, link_path);
213 | assert(err === 0);
214 |
215 | [st, err] = os.lstat(link_path);
216 | assert(err, 0);
217 | assert(st.mode & os.S_IFMT, os.S_IFLNK);
218 |
219 | [buf, err] = os.readlink(link_path);
220 | assert(err, 0);
221 | assert(buf, fname);
222 |
223 | assert(os.remove(link_path) === 0);
224 |
225 | [buf, err] = os.getcwd();
226 | assert(err, 0);
227 |
228 | [buf2, err] = os.realpath(".");
229 | assert(err, 0);
230 |
231 | assert(buf, buf2);
232 |
233 | assert(os.remove(fpath) === 0);
234 |
235 | fd = os.open(fpath, os.O_RDONLY);
236 | assert(fd < 0);
237 |
238 | assert(os.remove(fdir) === 0);
239 | }
240 |
241 | function test_os_exec()
242 | {
243 | var ret, fds, pid, f, status;
244 |
245 | ret = os.exec(["true"]);
246 | assert(ret, 0);
247 |
248 | ret = os.exec(["/bin/sh", "-c", "exit 1"], { usePath: false });
249 | assert(ret, 1);
250 |
251 | fds = os.pipe();
252 | pid = os.exec(["sh", "-c", "echo $FOO"], {
253 | stdout: fds[1],
254 | block: false,
255 | env: { FOO: "hello" },
256 | } );
257 | assert(pid >= 0);
258 | os.close(fds[1]); /* close the write end (as it is only in the child) */
259 | f = std.fdopen(fds[0], "r");
260 | assert(f.getline(), "hello");
261 | assert(f.getline(), null);
262 | f.close();
263 | [ret, status] = os.waitpid(pid, 0);
264 | assert(ret, pid);
265 | assert(status & 0x7f, 0); /* exited */
266 | assert(status >> 8, 0); /* exit code */
267 |
268 | pid = os.exec(["cat"], { block: false } );
269 | assert(pid >= 0);
270 | os.kill(pid, os.SIGTERM);
271 | [ret, status] = os.waitpid(pid, 0);
272 | assert(ret, pid);
273 | assert(status !== 0, true, `expect nonzero exit code (got ${status})`);
274 | assert(status & 0x7f, os.SIGTERM);
275 | }
276 |
277 | function test_timer()
278 | {
279 | var th, i;
280 |
281 | /* just test that a timer can be inserted and removed */
282 | th = [];
283 | for(i = 0; i < 3; i++)
284 | th[i] = os.setTimeout(function () { }, 1000);
285 | for(i = 0; i < 3; i++)
286 | os.clearTimeout(th[i]);
287 | }
288 |
289 | /* test closure variable handling when freeing asynchronous
290 | function */
291 | function test_async_gc()
292 | {
293 | (async function run () {
294 | let obj = {}
295 |
296 | let done = () => {
297 | obj
298 | std.gc();
299 | }
300 |
301 | Promise.resolve().then(done)
302 |
303 | const p = new Promise(() => {})
304 |
305 | await p
306 | })();
307 | }
308 |
309 | /* check that the promise async rejection handler is not invoked when
310 | the rejection is handled not too late after the promise
311 | rejection. */
312 | function test_async_promise_rejection()
313 | {
314 | var counter = 0;
315 | var p1, p2, p3;
316 | p1 = Promise.reject();
317 | p2 = Promise.reject();
318 | p3 = Promise.resolve();
319 | p1.catch(() => counter++);
320 | p2.catch(() => counter++);
321 | p3.then(() => counter++)
322 | os.setTimeout(() => { assert(counter, 3) }, 10);
323 | }
324 |
325 | test_printf();
326 | test_file1();
327 | test_file2();
328 | test_getline();
329 | test_popen();
330 | test_os();
331 | test_os_exec();
332 | test_timer();
333 | test_ext_json();
334 | test_async_gc();
335 | test_async_promise_rejection();
336 |
337 |
--------------------------------------------------------------------------------
/tests/test_worker.js:
--------------------------------------------------------------------------------
1 | /* os.Worker API test */
2 | import * as std from "std";
3 | import * as os from "os";
4 |
5 | function assert(actual, expected, message) {
6 | if (arguments.length == 1)
7 | expected = true;
8 |
9 | if (actual === expected)
10 | return;
11 |
12 | if (actual !== null && expected !== null
13 | && typeof actual == 'object' && typeof expected == 'object'
14 | && actual.toString() === expected.toString())
15 | return;
16 |
17 | throw Error("assertion failed: got |" + actual + "|" +
18 | ", expected |" + expected + "|" +
19 | (message ? " (" + message + ")" : ""));
20 | }
21 |
22 | var worker;
23 |
24 | function test_worker()
25 | {
26 | var counter;
27 |
28 | worker = new os.Worker("./test_worker_module.js");
29 |
30 | counter = 0;
31 | worker.onmessage = function (e) {
32 | var ev = e.data;
33 | // print("recv", JSON.stringify(ev));
34 | switch(ev.type) {
35 | case "num":
36 | assert(ev.num, counter);
37 | counter++;
38 | if (counter == 10) {
39 | /* test SharedArrayBuffer modification */
40 | let sab = new SharedArrayBuffer(10);
41 | let buf = new Uint8Array(sab);
42 | worker.postMessage({ type: "sab", buf: buf });
43 | }
44 | break;
45 | case "sab_done":
46 | {
47 | let buf = ev.buf;
48 | /* check that the SharedArrayBuffer was modified */
49 | assert(buf[2], 10);
50 | worker.postMessage({ type: "abort" });
51 | }
52 | break;
53 | case "done":
54 | /* terminate */
55 | worker.onmessage = null;
56 | break;
57 | }
58 | };
59 | }
60 |
61 |
62 | test_worker();
63 |
--------------------------------------------------------------------------------
/tests/test_worker_module.js:
--------------------------------------------------------------------------------
1 | /* Worker code for test_worker.js */
2 | import * as std from "std";
3 | import * as os from "os";
4 |
5 | var parent = os.Worker.parent;
6 |
7 | function handle_msg(e) {
8 | var ev = e.data;
9 | // print("child_recv", JSON.stringify(ev));
10 | switch(ev.type) {
11 | case "abort":
12 | parent.postMessage({ type: "done" });
13 | parent.onmessage = null; /* terminate the worker */
14 | break;
15 | case "sab":
16 | /* modify the SharedArrayBuffer */
17 | ev.buf[2] = 10;
18 | parent.postMessage({ type: "sab_done", buf: ev.buf });
19 | break;
20 | }
21 | }
22 |
23 | function worker_main() {
24 | var i;
25 |
26 | parent.onmessage = handle_msg;
27 | for(i = 0; i < 10; i++) {
28 | parent.postMessage({ type: "num", num: i });
29 | }
30 | }
31 |
32 | worker_main();
33 |
--------------------------------------------------------------------------------
/unicode_download.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | version="16.0.0"
5 | emoji_version="16.0"
6 | url="ftp://ftp.unicode.org/Public"
7 |
8 | files="CaseFolding.txt DerivedNormalizationProps.txt PropList.txt \
9 | SpecialCasing.txt CompositionExclusions.txt ScriptExtensions.txt \
10 | UnicodeData.txt DerivedCoreProperties.txt NormalizationTest.txt Scripts.txt \
11 | PropertyValueAliases.txt"
12 |
13 | mkdir -p unicode
14 |
15 | for f in $files; do
16 | g="${url}/${version}/ucd/${f}"
17 | wget $g -O unicode/$f
18 | done
19 |
20 | wget "${url}/${version}/ucd/emoji/emoji-data.txt" -O unicode/emoji-data.txt
21 |
22 | wget "${url}/emoji/${emoji_version}/emoji-sequences.txt" -O unicode/emoji-sequences.txt
23 | wget "${url}/emoji/${emoji_version}/emoji-zwj-sequences.txt" -O unicode/emoji-zwj-sequences.txt
24 |
--------------------------------------------------------------------------------
/unicode_gen_def.h:
--------------------------------------------------------------------------------
1 | #ifdef UNICODE_GENERAL_CATEGORY
2 | DEF(Cn, "Unassigned") /* must be zero */
3 | DEF(Lu, "Uppercase_Letter")
4 | DEF(Ll, "Lowercase_Letter")
5 | DEF(Lt, "Titlecase_Letter")
6 | DEF(Lm, "Modifier_Letter")
7 | DEF(Lo, "Other_Letter")
8 | DEF(Mn, "Nonspacing_Mark")
9 | DEF(Mc, "Spacing_Mark")
10 | DEF(Me, "Enclosing_Mark")
11 | DEF(Nd, "Decimal_Number,digit")
12 | DEF(Nl, "Letter_Number")
13 | DEF(No, "Other_Number")
14 | DEF(Sm, "Math_Symbol")
15 | DEF(Sc, "Currency_Symbol")
16 | DEF(Sk, "Modifier_Symbol")
17 | DEF(So, "Other_Symbol")
18 | DEF(Pc, "Connector_Punctuation")
19 | DEF(Pd, "Dash_Punctuation")
20 | DEF(Ps, "Open_Punctuation")
21 | DEF(Pe, "Close_Punctuation")
22 | DEF(Pi, "Initial_Punctuation")
23 | DEF(Pf, "Final_Punctuation")
24 | DEF(Po, "Other_Punctuation")
25 | DEF(Zs, "Space_Separator")
26 | DEF(Zl, "Line_Separator")
27 | DEF(Zp, "Paragraph_Separator")
28 | DEF(Cc, "Control,cntrl")
29 | DEF(Cf, "Format")
30 | DEF(Cs, "Surrogate")
31 | DEF(Co, "Private_Use")
32 | /* synthetic properties */
33 | DEF(LC, "Cased_Letter")
34 | DEF(L, "Letter")
35 | DEF(M, "Mark,Combining_Mark")
36 | DEF(N, "Number")
37 | DEF(S, "Symbol")
38 | DEF(P, "Punctuation,punct")
39 | DEF(Z, "Separator")
40 | DEF(C, "Other")
41 | #endif
42 |
43 | #ifdef UNICODE_SCRIPT
44 | /* scripts aliases names in PropertyValueAliases.txt */
45 | DEF(Unknown, "Zzzz")
46 | DEF(Adlam, "Adlm")
47 | DEF(Ahom, "Ahom")
48 | DEF(Anatolian_Hieroglyphs, "Hluw")
49 | DEF(Arabic, "Arab")
50 | DEF(Armenian, "Armn")
51 | DEF(Avestan, "Avst")
52 | DEF(Balinese, "Bali")
53 | DEF(Bamum, "Bamu")
54 | DEF(Bassa_Vah, "Bass")
55 | DEF(Batak, "Batk")
56 | DEF(Bengali, "Beng")
57 | DEF(Bhaiksuki, "Bhks")
58 | DEF(Bopomofo, "Bopo")
59 | DEF(Brahmi, "Brah")
60 | DEF(Braille, "Brai")
61 | DEF(Buginese, "Bugi")
62 | DEF(Buhid, "Buhd")
63 | DEF(Canadian_Aboriginal, "Cans")
64 | DEF(Carian, "Cari")
65 | DEF(Caucasian_Albanian, "Aghb")
66 | DEF(Chakma, "Cakm")
67 | DEF(Cham, "Cham")
68 | DEF(Cherokee, "Cher")
69 | DEF(Chorasmian, "Chrs")
70 | DEF(Common, "Zyyy")
71 | DEF(Coptic, "Copt,Qaac")
72 | DEF(Cuneiform, "Xsux")
73 | DEF(Cypriot, "Cprt")
74 | DEF(Cyrillic, "Cyrl")
75 | DEF(Cypro_Minoan, "Cpmn")
76 | DEF(Deseret, "Dsrt")
77 | DEF(Devanagari, "Deva")
78 | DEF(Dives_Akuru, "Diak")
79 | DEF(Dogra, "Dogr")
80 | DEF(Duployan, "Dupl")
81 | DEF(Egyptian_Hieroglyphs, "Egyp")
82 | DEF(Elbasan, "Elba")
83 | DEF(Elymaic, "Elym")
84 | DEF(Ethiopic, "Ethi")
85 | DEF(Garay, "Gara")
86 | DEF(Georgian, "Geor")
87 | DEF(Glagolitic, "Glag")
88 | DEF(Gothic, "Goth")
89 | DEF(Grantha, "Gran")
90 | DEF(Greek, "Grek")
91 | DEF(Gujarati, "Gujr")
92 | DEF(Gunjala_Gondi, "Gong")
93 | DEF(Gurmukhi, "Guru")
94 | DEF(Gurung_Khema, "Gukh")
95 | DEF(Han, "Hani")
96 | DEF(Hangul, "Hang")
97 | DEF(Hanifi_Rohingya, "Rohg")
98 | DEF(Hanunoo, "Hano")
99 | DEF(Hatran, "Hatr")
100 | DEF(Hebrew, "Hebr")
101 | DEF(Hiragana, "Hira")
102 | DEF(Imperial_Aramaic, "Armi")
103 | DEF(Inherited, "Zinh,Qaai")
104 | DEF(Inscriptional_Pahlavi, "Phli")
105 | DEF(Inscriptional_Parthian, "Prti")
106 | DEF(Javanese, "Java")
107 | DEF(Kaithi, "Kthi")
108 | DEF(Kannada, "Knda")
109 | DEF(Katakana, "Kana")
110 | DEF(Kawi, "Kawi")
111 | DEF(Kayah_Li, "Kali")
112 | DEF(Kharoshthi, "Khar")
113 | DEF(Khmer, "Khmr")
114 | DEF(Khojki, "Khoj")
115 | DEF(Khitan_Small_Script, "Kits")
116 | DEF(Khudawadi, "Sind")
117 | DEF(Kirat_Rai, "Krai")
118 | DEF(Lao, "Laoo")
119 | DEF(Latin, "Latn")
120 | DEF(Lepcha, "Lepc")
121 | DEF(Limbu, "Limb")
122 | DEF(Linear_A, "Lina")
123 | DEF(Linear_B, "Linb")
124 | DEF(Lisu, "Lisu")
125 | DEF(Lycian, "Lyci")
126 | DEF(Lydian, "Lydi")
127 | DEF(Makasar, "Maka")
128 | DEF(Mahajani, "Mahj")
129 | DEF(Malayalam, "Mlym")
130 | DEF(Mandaic, "Mand")
131 | DEF(Manichaean, "Mani")
132 | DEF(Marchen, "Marc")
133 | DEF(Masaram_Gondi, "Gonm")
134 | DEF(Medefaidrin, "Medf")
135 | DEF(Meetei_Mayek, "Mtei")
136 | DEF(Mende_Kikakui, "Mend")
137 | DEF(Meroitic_Cursive, "Merc")
138 | DEF(Meroitic_Hieroglyphs, "Mero")
139 | DEF(Miao, "Plrd")
140 | DEF(Modi, "Modi")
141 | DEF(Mongolian, "Mong")
142 | DEF(Mro, "Mroo")
143 | DEF(Multani, "Mult")
144 | DEF(Myanmar, "Mymr")
145 | DEF(Nabataean, "Nbat")
146 | DEF(Nag_Mundari, "Nagm")
147 | DEF(Nandinagari, "Nand")
148 | DEF(New_Tai_Lue, "Talu")
149 | DEF(Newa, "Newa")
150 | DEF(Nko, "Nkoo")
151 | DEF(Nushu, "Nshu")
152 | DEF(Nyiakeng_Puachue_Hmong, "Hmnp")
153 | DEF(Ogham, "Ogam")
154 | DEF(Ol_Chiki, "Olck")
155 | DEF(Ol_Onal, "Onao")
156 | DEF(Old_Hungarian, "Hung")
157 | DEF(Old_Italic, "Ital")
158 | DEF(Old_North_Arabian, "Narb")
159 | DEF(Old_Permic, "Perm")
160 | DEF(Old_Persian, "Xpeo")
161 | DEF(Old_Sogdian, "Sogo")
162 | DEF(Old_South_Arabian, "Sarb")
163 | DEF(Old_Turkic, "Orkh")
164 | DEF(Old_Uyghur, "Ougr")
165 | DEF(Oriya, "Orya")
166 | DEF(Osage, "Osge")
167 | DEF(Osmanya, "Osma")
168 | DEF(Pahawh_Hmong, "Hmng")
169 | DEF(Palmyrene, "Palm")
170 | DEF(Pau_Cin_Hau, "Pauc")
171 | DEF(Phags_Pa, "Phag")
172 | DEF(Phoenician, "Phnx")
173 | DEF(Psalter_Pahlavi, "Phlp")
174 | DEF(Rejang, "Rjng")
175 | DEF(Runic, "Runr")
176 | DEF(Samaritan, "Samr")
177 | DEF(Saurashtra, "Saur")
178 | DEF(Sharada, "Shrd")
179 | DEF(Shavian, "Shaw")
180 | DEF(Siddham, "Sidd")
181 | DEF(SignWriting, "Sgnw")
182 | DEF(Sinhala, "Sinh")
183 | DEF(Sogdian, "Sogd")
184 | DEF(Sora_Sompeng, "Sora")
185 | DEF(Soyombo, "Soyo")
186 | DEF(Sundanese, "Sund")
187 | DEF(Sunuwar, "Sunu")
188 | DEF(Syloti_Nagri, "Sylo")
189 | DEF(Syriac, "Syrc")
190 | DEF(Tagalog, "Tglg")
191 | DEF(Tagbanwa, "Tagb")
192 | DEF(Tai_Le, "Tale")
193 | DEF(Tai_Tham, "Lana")
194 | DEF(Tai_Viet, "Tavt")
195 | DEF(Takri, "Takr")
196 | DEF(Tamil, "Taml")
197 | DEF(Tangut, "Tang")
198 | DEF(Telugu, "Telu")
199 | DEF(Thaana, "Thaa")
200 | DEF(Thai, "Thai")
201 | DEF(Tibetan, "Tibt")
202 | DEF(Tifinagh, "Tfng")
203 | DEF(Tirhuta, "Tirh")
204 | DEF(Tangsa, "Tnsa")
205 | DEF(Todhri, "Todr")
206 | DEF(Toto, "Toto")
207 | DEF(Tulu_Tigalari, "Tutg")
208 | DEF(Ugaritic, "Ugar")
209 | DEF(Vai, "Vaii")
210 | DEF(Vithkuqi, "Vith")
211 | DEF(Wancho, "Wcho")
212 | DEF(Warang_Citi, "Wara")
213 | DEF(Yezidi, "Yezi")
214 | DEF(Yi, "Yiii")
215 | DEF(Zanabazar_Square, "Zanb")
216 | #endif
217 |
218 | #ifdef UNICODE_PROP_LIST
219 | /* Prop list not exported to regexp */
220 | DEF(Hyphen, "")
221 | DEF(Other_Math, "")
222 | DEF(Other_Alphabetic, "")
223 | DEF(Other_Lowercase, "")
224 | DEF(Other_Uppercase, "")
225 | DEF(Other_Grapheme_Extend, "")
226 | DEF(Other_Default_Ignorable_Code_Point, "")
227 | DEF(Other_ID_Start, "")
228 | DEF(Other_ID_Continue, "")
229 | DEF(Prepended_Concatenation_Mark, "")
230 | /* additional computed properties for smaller tables */
231 | DEF(ID_Continue1, "")
232 | DEF(XID_Start1, "")
233 | DEF(XID_Continue1, "")
234 | DEF(Changes_When_Titlecased1, "")
235 | DEF(Changes_When_Casefolded1, "")
236 | DEF(Changes_When_NFKC_Casefolded1, "")
237 | DEF(Basic_Emoji1, "")
238 | DEF(Basic_Emoji2, "")
239 | DEF(RGI_Emoji_Modifier_Sequence, "")
240 | DEF(RGI_Emoji_Flag_Sequence, "")
241 | DEF(Emoji_Keycap_Sequence, "")
242 |
243 | /* Prop list exported to JS */
244 | DEF(ASCII_Hex_Digit, "AHex")
245 | DEF(Bidi_Control, "Bidi_C")
246 | DEF(Dash, "")
247 | DEF(Deprecated, "Dep")
248 | DEF(Diacritic, "Dia")
249 | DEF(Extender, "Ext")
250 | DEF(Hex_Digit, "Hex")
251 | DEF(IDS_Unary_Operator, "IDSU")
252 | DEF(IDS_Binary_Operator, "IDSB")
253 | DEF(IDS_Trinary_Operator, "IDST")
254 | DEF(Ideographic, "Ideo")
255 | DEF(Join_Control, "Join_C")
256 | DEF(Logical_Order_Exception, "LOE")
257 | DEF(Modifier_Combining_Mark, "MCM")
258 | DEF(Noncharacter_Code_Point, "NChar")
259 | DEF(Pattern_Syntax, "Pat_Syn")
260 | DEF(Pattern_White_Space, "Pat_WS")
261 | DEF(Quotation_Mark, "QMark")
262 | DEF(Radical, "")
263 | DEF(Regional_Indicator, "RI")
264 | DEF(Sentence_Terminal, "STerm")
265 | DEF(Soft_Dotted, "SD")
266 | DEF(Terminal_Punctuation, "Term")
267 | DEF(Unified_Ideograph, "UIdeo")
268 | DEF(Variation_Selector, "VS")
269 | DEF(White_Space, "space")
270 | DEF(Bidi_Mirrored, "Bidi_M")
271 | DEF(Emoji, "")
272 | DEF(Emoji_Component, "EComp")
273 | DEF(Emoji_Modifier, "EMod")
274 | DEF(Emoji_Modifier_Base, "EBase")
275 | DEF(Emoji_Presentation, "EPres")
276 | DEF(Extended_Pictographic, "ExtPict")
277 | DEF(Default_Ignorable_Code_Point, "DI")
278 | DEF(ID_Start, "IDS")
279 | DEF(Case_Ignorable, "CI")
280 |
281 | /* other binary properties */
282 | DEF(ASCII,"")
283 | DEF(Alphabetic, "Alpha")
284 | DEF(Any, "")
285 | DEF(Assigned,"")
286 | DEF(Cased, "")
287 | DEF(Changes_When_Casefolded, "CWCF")
288 | DEF(Changes_When_Casemapped, "CWCM")
289 | DEF(Changes_When_Lowercased, "CWL")
290 | DEF(Changes_When_NFKC_Casefolded, "CWKCF")
291 | DEF(Changes_When_Titlecased, "CWT")
292 | DEF(Changes_When_Uppercased, "CWU")
293 | DEF(Grapheme_Base, "Gr_Base")
294 | DEF(Grapheme_Extend, "Gr_Ext")
295 | DEF(ID_Continue, "IDC")
296 | DEF(ID_Compat_Math_Start, "")
297 | DEF(ID_Compat_Math_Continue, "")
298 | DEF(InCB, "")
299 | DEF(Lowercase, "Lower")
300 | DEF(Math, "")
301 | DEF(Uppercase, "Upper")
302 | DEF(XID_Continue, "XIDC")
303 | DEF(XID_Start, "XIDS")
304 |
305 | /* internal tables with index */
306 | DEF(Cased1, "")
307 |
308 | #endif
309 |
310 | #ifdef UNICODE_SEQUENCE_PROP_LIST
311 | DEF(Basic_Emoji)
312 | DEF(Emoji_Keycap_Sequence)
313 | DEF(RGI_Emoji_Modifier_Sequence)
314 | DEF(RGI_Emoji_Flag_Sequence)
315 | DEF(RGI_Emoji_Tag_Sequence)
316 | DEF(RGI_Emoji_ZWJ_Sequence)
317 | DEF(RGI_Emoji)
318 | #endif
319 |
--------------------------------------------------------------------------------