├── .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 | --------------------------------------------------------------------------------