├── .gitignore ├── quickjs ├── VERSION ├── patches │ ├── 2025-04-26-freebsd.patch │ ├── 2025-04-26-getpropertyvalue_uninitialized_read_fix.patch │ ├── 2025-04-26-getclassid-const.patch │ └── 2025-04-26-unhandled_rejection.patch ├── update.sh ├── CMakeLists.txt ├── LICENSE ├── libregexp-opcode.h ├── libregexp.h ├── quickjs-libc.h ├── list.h ├── dtoa.h ├── libunicode.h ├── quickjs-atom.h ├── cutils.h ├── quickjs-opcode.h ├── cutils.c └── quickjs.h ├── .github └── workflows │ ├── doxygen.yml │ ├── valgrind.yml │ ├── quickjsdll.yml │ └── cxx.yml ├── test ├── CMakeLists.txt ├── jobs.cpp ├── enum.cpp ├── conversions.cpp ├── point.cpp ├── example.cpp ├── unhandled_rejection.cpp ├── multicontext.cpp ├── value.cpp ├── module_loader.cpp ├── variant.cpp ├── function_call.cpp ├── exception.cpp ├── class.cpp └── inheritance.cpp ├── CMakeLists.txt ├── readme.md ├── qjs.cpp └── binding-generator └── generator.py /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .cache 3 | -------------------------------------------------------------------------------- /quickjs/VERSION: -------------------------------------------------------------------------------- 1 | 2025-04-26 2 | -------------------------------------------------------------------------------- /quickjs/patches/2025-04-26-freebsd.patch: -------------------------------------------------------------------------------- 1 | diff --git a/quickjs/quickjs-libc.c b/quickjs/quickjs-libc.c 2 | index 023d895..2387a45 100644 3 | --- a/quickjs/quickjs-libc.c 4 | +++ b/quickjs/quickjs-libc.c 5 | @@ -48,7 +48,9 @@ 6 | #include 7 | 8 | #if defined(__FreeBSD__) 9 | +__BEGIN_DECLS 10 | extern char **environ; 11 | +__END_DECLS 12 | #endif 13 | 14 | #if defined(__APPLE__) || defined(__FreeBSD__) 15 | -------------------------------------------------------------------------------- /quickjs/patches/2025-04-26-getpropertyvalue_uninitialized_read_fix.patch: -------------------------------------------------------------------------------- 1 | diff --git a/quickjs/quickjs.c b/quickjs/quickjs.c 2 | index caad931..325c6dd 100644 3 | --- a/quickjs/quickjs.c 4 | +++ b/quickjs/quickjs.c 5 | @@ -8367,6 +8367,8 @@ static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj, 6 | uint32_t idx; 7 | /* fast path for array access */ 8 | p = JS_VALUE_GET_OBJ(this_obj); 9 | + if (unlikely(!p->fast_array)) 10 | + goto slow_path; 11 | idx = JS_VALUE_GET_INT(prop); 12 | switch(p->class_id) { 13 | case JS_CLASS_ARRAY: 14 | -------------------------------------------------------------------------------- /.github/workflows/doxygen.yml: -------------------------------------------------------------------------------- 1 | name: Doxygen 2 | on: 3 | push: 4 | branches: 5 | - master 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | with: 13 | submodules: recursive 14 | - name: Doxygen install 15 | run: sudo apt-get install -y doxygen graphviz 16 | - name: Doxygen 17 | run: doxygen 18 | - name: Deploy 19 | uses: peaceiris/actions-gh-pages@v3 20 | with: 21 | personal_token: ${{ secrets.TOKEN }} 22 | publish_dir: ./html 23 | publish_branch: gh-pages 24 | force_orphan: true -------------------------------------------------------------------------------- /quickjs/update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Download and extract latest version of quickjs 3 | set -euxo pipefail 4 | 5 | ver="$(curl -s --compressed -L https://bellard.org/quickjs/ | grep --perl-regexp --only-matching --max-count=1 '\d{4}-\d{2}-\d{2}')" 6 | 7 | # list of files to extract if no arguments are provided 8 | [ $# == 0 ] && set -- *.c *.h VERSION 9 | 10 | curl -s -L "https://bellard.org/quickjs/quickjs-${ver}.tar.xz" | unxz | tar --strip-components=1 -xf - -- "${@/#/quickjs-${ver}\/}" 11 | 12 | git apply --verbose -- patches/*.patch 13 | 14 | # commit (interactive) 15 | git commit -m "update quickjs to ${ver}" -e -- $@ 16 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | macro(make_test name) 2 | add_executable(${name} ${name}.cpp) 3 | target_link_libraries(${name} quickjspp quickjs-dumpleaks) 4 | add_test(${name} ${name}) 5 | # try to compile with -DCONFIG_CHECK_JSVALUE 6 | add_library(${name}-checkjsv OBJECT ${name}.cpp) 7 | target_compile_definitions(${name}-checkjsv PRIVATE CONFIG_CHECK_JSVALUE=1) 8 | target_link_libraries(${name}-checkjsv quickjspp) 9 | endmacro() 10 | 11 | foreach(test 12 | value class exception example multicontext conversions point variant function_call inheritance jobs unhandled_rejection module_loader 13 | enum 14 | ) 15 | make_test(${test}) 16 | endforeach() 17 | 18 | -------------------------------------------------------------------------------- /.github/workflows/valgrind.yml: -------------------------------------------------------------------------------- 1 | name: Valgrind 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | with: 11 | submodules: recursive 12 | - name: install 13 | run: sudo apt-get update; sudo apt-get install -y valgrind 14 | - name: configure 15 | run: echo 'include(Dart)' >> CMakeLists.txt && cmake -S . -B build_dir -Wdev -DCMAKE_BUILD_TYPE=Debug -DMEMORYCHECK_COMMAND_OPTIONS="--leak-check=full --track-origins=yes --error-exitcode=1" 16 | - name: build 17 | run: cmake --build build_dir --verbose 18 | - name: test 19 | run: ctest -T memcheck --output-on-failure . 20 | working-directory: build_dir 21 | - name: logs 22 | run: cat build_dir/Testing/Temporary/MemoryChecker.*.log 23 | if: always() 24 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(quickjspp LANGUAGES CXX) 3 | 4 | #set(CMAKE_CXX_STANDARD 17) 5 | set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) 6 | 7 | if(CMAKE_COMPILER_IS_GNUCC) 8 | add_compile_options(-Wall -Wno-unused-parameter) 9 | endif() 10 | 11 | add_subdirectory(quickjs) 12 | 13 | add_library(quickjspp INTERFACE) 14 | target_link_libraries(quickjspp INTERFACE quickjs ${CMAKE_REQUIRED_LIBRARIES}) 15 | target_compile_features(quickjspp INTERFACE cxx_std_17) 16 | target_include_directories(quickjspp INTERFACE .) 17 | set_target_properties(quickjspp PROPERTIES PUBLIC_HEADER quickjspp.hpp) 18 | 19 | add_executable(qjs qjs.cpp) 20 | target_link_libraries(qjs quickjspp) 21 | 22 | # cmake -DBUILD_TESTING=OFF to disable tests 23 | include(CTest) 24 | if(BUILD_TESTING) 25 | add_subdirectory(test) 26 | endif() 27 | 28 | install(TARGETS quickjspp qjs) 29 | -------------------------------------------------------------------------------- /quickjs/patches/2025-04-26-getclassid-const.patch: -------------------------------------------------------------------------------- 1 | diff --git a/quickjs/quickjs.c b/quickjs/quickjs.c 2 | index fa7c24a..0535169 100644 3 | --- a/quickjs/quickjs.c 4 | +++ b/quickjs/quickjs.c 5 | @@ -3320,7 +3320,7 @@ JSClassID JS_NewClassID(JSClassID *pclass_id) 6 | return class_id; 7 | } 8 | 9 | -JSClassID JS_GetClassID(JSValue v) 10 | +JSClassID JS_GetClassID(JSValueConst v) 11 | { 12 | JSObject *p; 13 | if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT) 14 | diff --git a/quickjs/quickjs.h b/quickjs/quickjs.h 15 | index 2083f73..80aacc4 100644 16 | --- a/quickjs/quickjs.h 17 | +++ b/quickjs/quickjs.h 18 | @@ -544,7 +544,7 @@ typedef struct JSClassDef { 19 | #define JS_INVALID_CLASS_ID 0 20 | JSClassID JS_NewClassID(JSClassID *pclass_id); 21 | /* Returns the class ID if `v` is an object, otherwise returns JS_INVALID_CLASS_ID. */ 22 | -JSClassID JS_GetClassID(JSValue v); 23 | +JSClassID JS_GetClassID(JSValueConst v); 24 | int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def); 25 | int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id); 26 | 27 | -------------------------------------------------------------------------------- /quickjs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(quickjs LANGUAGES C) 2 | 3 | file(STRINGS VERSION version) 4 | 5 | set(quickjs_src 6 | cutils.c 7 | dtoa.c 8 | libregexp.c 9 | libunicode.c 10 | quickjs-libc.c 11 | quickjs.c 12 | ) 13 | 14 | set(quickjs_def CONFIG_VERSION="${version}" _GNU_SOURCE CONFIG_BIGNUM) 15 | 16 | add_library(quickjs ${quickjs_src}) 17 | target_compile_definitions(quickjs PRIVATE ${quickjs_def} ) 18 | set_target_properties(quickjs PROPERTIES PUBLIC_HEADER "quickjs.h;quickjs-libc.h") 19 | 20 | add_library(quickjs-dumpleaks ${quickjs_src}) 21 | target_compile_definitions(quickjs-dumpleaks PRIVATE ${quickjs_def} DUMP_LEAKS=1) 22 | 23 | if(UNIX OR MINGW) 24 | find_package(Threads) 25 | target_link_libraries(quickjs ${CMAKE_DL_LIBS} m Threads::Threads) 26 | target_link_libraries(quickjs-dumpleaks ${CMAKE_DL_LIBS} m Threads::Threads) 27 | endif() 28 | 29 | # install 30 | include(GNUInstallDirs) 31 | install(TARGETS quickjs 32 | PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/quickjs 33 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/quickjs 34 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/quickjs 35 | ) 36 | -------------------------------------------------------------------------------- /quickjs/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 | -------------------------------------------------------------------------------- /test/jobs.cpp: -------------------------------------------------------------------------------- 1 | #include "quickjspp.hpp" 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | qjs::Runtime runtime; 8 | qjs::Context context(runtime); 9 | 10 | context.global()["nextTick"] = [&context](std::function f) { 11 | context.enqueueJob(std::move(f)); 12 | }; 13 | 14 | bool called = false; 15 | context.global()["testFcn"] = [&called]() { 16 | called = true; 17 | }; 18 | 19 | qjs::Value caller = context.eval(R"xxx( 20 | nextTick(testFcn); 21 | )xxx"); 22 | 23 | assert(!called && "`testFcn` should not be called yet"); 24 | 25 | while (runtime.isJobPending()) { 26 | runtime.executePendingJob(); 27 | } 28 | 29 | assert(called && "`testFcn` should have been called"); 30 | 31 | context.enqueueJob([](){ 32 | throw std::runtime_error("some error"); 33 | }); 34 | 35 | try { 36 | while (runtime.isJobPending()) { 37 | runtime.executePendingJob(); 38 | } 39 | assert(false && "Job execution should have failed"); 40 | } catch (qjs::exception const & exc) { 41 | assert(&exc.context() == &context && "Exception should contain context information"); 42 | } 43 | // Check that not executed jobs won't introduce memory leaks 44 | context.enqueueJob([](){ 45 | assert(false && "This job will not be called"); 46 | }); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /test/enum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "quickjspp.hpp" 4 | 5 | enum TestEnum : int64_t{ 6 | TestEnum_A, 7 | TestEnum_B = (1ll << 51), 8 | TestEnum_C, 9 | }; 10 | 11 | class TestClass { 12 | public: 13 | TestEnum e = TestEnum_C; 14 | 15 | TestEnum getE() { 16 | return e; 17 | } 18 | }; 19 | 20 | void println(qjs::rest args) { 21 | for (auto const &arg: args) std::cout << arg << " "; 22 | std::cout << "\n"; 23 | } 24 | 25 | int main() { 26 | qjs::Runtime runtime; 27 | qjs::Context context(runtime); 28 | try { 29 | auto &module = context.addModule("MyModule"); 30 | module.function<&println>("println"); 31 | module.class_("TestClass") 32 | .constructor<>() 33 | .fun<&TestClass::getE>("getE"); 34 | // import module 35 | context.eval(R"xxx( 36 | import * as my from 'MyModule'; 37 | globalThis.my = my; 38 | )xxx", 39 | "", JS_EVAL_TYPE_MODULE); 40 | context.eval(R"xxx( 41 | let v1 = new my.TestClass(); 42 | let e = v1.getE(); 43 | my.println("enum value "+e); 44 | )xxx"); 45 | assert(context.eval("e").as() == TestEnum_C); 46 | } catch (qjs::exception) { 47 | auto exc = context.getException(); 48 | std::cerr << (std::string) exc << std::endl; 49 | if ((bool) exc["stack"]) std::cerr << (std::string) exc["stack"] << std::endl; 50 | return 1; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /.github/workflows/quickjsdll.yml: -------------------------------------------------------------------------------- 1 | name: QuickJS MinGW DLL build 2 | 3 | on: 4 | push: 5 | paths: 6 | - 'quickjs/**' 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | cflags: [ "-flto -O2 -DNDEBUG", "-flto -Os -DNDEBUG", "-flto -O3 -DNDEBUG", "-O3 -DNDEBUG", "-g -DDUMP_LEAKS=1" ] 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | with: 19 | submodules: recursive 20 | - name: install mingw 21 | run: sudo apt-get update ; sudo apt-get install -y mingw-w64 22 | - name: build dlls 23 | run: | 24 | mkdir -p bin 25 | # generate def file 26 | gcc -shared quickjs/*.c -DCONFIG_VERSION=\"$(cat quickjs/VERSION)\" -DCONFIG_BIGNUM -D_GNU_SOURCE=1 -fPIC -o libquickjs.so 27 | # export only symbols with "js" in them 28 | echo 'EXPORTS' > bin/libquickjs.def 29 | nm -D --defined-only -f posix libquickjs.so | grep -i js | awk '{print $1}' >> bin/libquickjs.def 30 | i686-w64-mingw32-gcc -shared -static quickjs/*.c bin/libquickjs.def -DCONFIG_VERSION=\"$(cat quickjs/VERSION)\" -DCONFIG_BIGNUM -D_GNU_SOURCE=1 -o bin/libquickjs32.dll -Wl,--out-implib,bin/libquickjs32.a -pthread -s ${{ matrix.cflags }} 31 | x86_64-w64-mingw32-gcc -shared -static quickjs/*.c bin/libquickjs.def -DCONFIG_VERSION=\"$(cat quickjs/VERSION)\" -DCONFIG_BIGNUM -D_GNU_SOURCE=1 -o bin/libquickjs64.dll -Wl,--out-implib,bin/libquickjs64.a -pthread -s ${{ matrix.cflags }} 32 | shell: bash 33 | - uses: actions/upload-artifact@v2 34 | with: 35 | name: dlls ${{matrix.cflags}} 36 | path: bin -------------------------------------------------------------------------------- /test/conversions.cpp: -------------------------------------------------------------------------------- 1 | #include "quickjspp.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | void test_conv(qjs::Context& context, T x) 8 | { 9 | auto jsx = context.newValue(x); 10 | 11 | auto x2 = static_cast(jsx); 12 | 13 | if(!(x2 == x)) 14 | throw std::exception(); 15 | 16 | if constexpr (std::is_integral_v && !std::is_same_v) 17 | { 18 | auto x3 = static_cast(jsx); 19 | if(!(x3 == x)) 20 | throw std::exception(); 21 | } 22 | } 23 | 24 | template 25 | void test_num(qjs::Context& context) 26 | { 27 | test_conv(context, std::numeric_limits::min()+1); 28 | test_conv(context, std::numeric_limits::max()-1); 29 | test_conv(context, std::numeric_limits::min()); 30 | test_conv(context, std::numeric_limits::max()); 31 | 32 | } 33 | 34 | int main() 35 | { 36 | qjs::Runtime runtime; 37 | qjs::Context context(runtime); 38 | try 39 | { 40 | test_num(context); 41 | test_num(context); 42 | test_num(context); 43 | 44 | // int64 is represented as double... 45 | test_conv(context, -(1ll << 52)); 46 | test_conv(context, -(1ll << 52) + 1); 47 | test_conv(context, (1ll << 52)); 48 | test_conv(context, (1ll << 52) - 1); 49 | 50 | 51 | test_num(context); 52 | //test_num(context); 53 | 54 | } 55 | catch(qjs::exception) 56 | { 57 | auto exc = context.getException(); 58 | std::cerr << (std::string) exc << std::endl; 59 | if((bool) exc["stack"]) 60 | std::cerr << (std::string) exc["stack"] << std::endl; 61 | return 1; 62 | } 63 | } -------------------------------------------------------------------------------- /test/point.cpp: -------------------------------------------------------------------------------- 1 | #include "quickjspp.hpp" 2 | #include 3 | #include 4 | 5 | class Point 6 | { 7 | public: 8 | int x, y; 9 | Point(int x, int y) : x(x), y(y) {} 10 | 11 | double norm() const 12 | { 13 | return std::sqrt((double)x * x + double(y) * y); 14 | } 15 | }; 16 | 17 | 18 | int main() 19 | { 20 | qjs::Runtime runtime; 21 | qjs::Context context(runtime); 22 | try 23 | { 24 | // export classes as a module 25 | auto& module = context.addModule("MyModule"); 26 | module.class_("Point") 27 | .constructor() 28 | .fun<&Point::x>("x") 29 | .fun<&Point::y>("y") 30 | .fun<&Point::norm>("norm"); 31 | // import module 32 | context.eval(R"xxx( 33 | import { Point } from "MyModule"; 34 | 35 | function assert(b, str) 36 | { 37 | if (b) { 38 | return; 39 | } else { 40 | throw Error("assertion failed: " + str); 41 | } 42 | } 43 | 44 | class ColorPoint extends Point { 45 | constructor(x, y, color) { 46 | super(x, y); 47 | this.color = color; 48 | } 49 | get_color() { 50 | return this.color; 51 | } 52 | }; 53 | 54 | function main() 55 | { 56 | var pt, pt2; 57 | 58 | pt = new Point(2, 3); 59 | assert(pt.x === 2); 60 | assert(pt.y === 3); 61 | pt.x = 4; 62 | assert(pt.x === 4); 63 | assert(pt.norm() == 5); 64 | 65 | pt2 = new ColorPoint(2, 3, 0xffffff); 66 | assert(pt2.x === 2); 67 | assert(pt2.color === 0xffffff); 68 | assert(pt2.get_color() === 0xffffff); 69 | } 70 | 71 | main(); 72 | )xxx", "", JS_EVAL_TYPE_MODULE); 73 | } 74 | catch(qjs::exception) 75 | { 76 | auto exc = context.getException(); 77 | std::cerr << (std::string) exc << std::endl; 78 | if((bool) exc["stack"]) 79 | std::cerr << (std::string) exc["stack"] << std::endl; 80 | return 1; 81 | } 82 | } -------------------------------------------------------------------------------- /test/example.cpp: -------------------------------------------------------------------------------- 1 | #include "quickjspp.hpp" 2 | #include 3 | 4 | class MyClass 5 | { 6 | public: 7 | MyClass() {} 8 | MyClass(std::vector) {} 9 | 10 | double member_variable = 5.5; 11 | std::string member_function(const std::string& s) { return "Hello, " + s; } 12 | }; 13 | 14 | void println(qjs::rest args) { 15 | for (auto const & arg : args) std::cout << arg << " "; 16 | std::cout << "\n"; 17 | } 18 | 19 | int main() 20 | { 21 | qjs::Runtime runtime; 22 | qjs::Context context(runtime); 23 | try 24 | { 25 | // export classes as a module 26 | auto& module = context.addModule("MyModule"); 27 | module.function<&println>("println"); 28 | module.class_("MyClass") 29 | .constructor<>() 30 | .constructor>("MyClassA") 31 | .fun<&MyClass::member_variable>("member_variable") 32 | .fun<&MyClass::member_function>("member_function"); 33 | // import module 34 | context.eval(R"xxx( 35 | import * as my from 'MyModule'; 36 | globalThis.my = my; 37 | )xxx", "", JS_EVAL_TYPE_MODULE); 38 | // evaluate js code 39 | context.eval(R"xxx( 40 | let v1 = new my.MyClass(); 41 | v1.member_variable = 1; 42 | let v2 = new my.MyClassA([1,2,3]); 43 | function my_callback(str) { 44 | my.println("at callback:", v2.member_function(str)); 45 | } 46 | )xxx"); 47 | 48 | // callback 49 | auto cb = (std::function) context.eval("my_callback"); 50 | cb("world"); 51 | 52 | // passing c++ objects to JS 53 | auto lambda = context.eval("x=>my.println(x.member_function('lambda'))").as)>>(); 54 | auto v3 = qjs::make_shared(context.ctx, std::vector{1,2,3}); 55 | lambda(v3); 56 | } 57 | catch(qjs::exception) 58 | { 59 | auto exc = context.getException(); 60 | std::cerr << (std::string) exc << std::endl; 61 | if((bool) exc["stack"]) 62 | std::cerr << (std::string) exc["stack"] << std::endl; 63 | return 1; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /test/unhandled_rejection.cpp: -------------------------------------------------------------------------------- 1 | #include "quickjspp.hpp" 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | qjs::Runtime runtime; 8 | qjs::Context context(runtime); 9 | 10 | context.global()["nextTick"] = [&context](std::function f) { 11 | context.enqueueJob(std::move(f)); 12 | }; 13 | 14 | bool called = false; 15 | context.onUnhandledPromiseRejection = [&called](qjs::Value reason) { 16 | called = true; 17 | }; 18 | 19 | // Catch the rejection 20 | called = false; 21 | context.eval(R"xxx( 22 | (() => { 23 | const p = new Promise((resolve, reject) => { 24 | nextTick(() => { 25 | reject(123); 26 | }) 27 | }); 28 | p.catch(() => {/* no-op */}); 29 | })(); 30 | )xxx"); 31 | 32 | while (runtime.isJobPending()) { 33 | runtime.executePendingJob(); 34 | } 35 | 36 | assert(!called && "Unhandled Promise rejection should not have been called"); 37 | 38 | // Catch the rejection, but only one *after* it happens. 39 | called = false; 40 | context.eval(R"xxx( 41 | (() => { 42 | const p = new Promise((resolve, reject) => { 43 | reject(123); 44 | nextTick(() => { 45 | p.catch(() => {/* no-op */}); 46 | }); 47 | }); 48 | })(); 49 | )xxx"); 50 | 51 | while (runtime.isJobPending()) { 52 | runtime.executePendingJob(); 53 | } 54 | 55 | assert(!called && "Unhandled Promise rejection should not have been called"); 56 | 57 | // Do not catch the rejection 58 | called = false; 59 | context.eval(R"xxx( 60 | (() => { 61 | const p = new Promise((resolve, reject) => { 62 | reject(123); 63 | nextTick(() => { 64 | p.then(() => {/* no-op */}) 65 | }); 66 | }); 67 | })(); 68 | )xxx"); 69 | 70 | assert(!called && "Unhandled Promise rejection should not have been called yet"); 71 | 72 | while (runtime.isJobPending()) { 73 | runtime.executePendingJob(); 74 | } 75 | 76 | assert(called && "Unhandled Promise rejection should have been called"); 77 | 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /test/multicontext.cpp: -------------------------------------------------------------------------------- 1 | #include "quickjspp.hpp" 2 | #include 3 | 4 | class MyClass 5 | { 6 | public: 7 | MyClass() {} 8 | 9 | void print_context(qjs::Value value) { std::cout << "Context: " << value.ctx << '\n'; } 10 | }; 11 | 12 | void println(const std::string& str) { std::cout << str << std::endl; } 13 | 14 | static void glue(qjs::Context::Module& module) 15 | { 16 | module.function<&println>("println"); 17 | module.class_("MyClass") 18 | .constructor<>() 19 | .fun<&MyClass::print_context>("print_context"); 20 | } 21 | 22 | 23 | int main() 24 | { 25 | qjs::Runtime runtime; 26 | qjs::Context context1(runtime); 27 | qjs::Context context2(runtime); 28 | qjs::Value val = JS_UNDEFINED, mc = JS_UNDEFINED; 29 | try 30 | { 31 | // export classes as a module 32 | glue(context1.addModule("MyModule")); 33 | // evaluate js code 34 | context1.eval(R"xxx( 35 | import * as my from 'MyModule'; 36 | globalThis.mc = new my.MyClass(); 37 | mc.print_context(undefined); 38 | )xxx", "", JS_EVAL_TYPE_MODULE); 39 | 40 | context1.global()["val"] = context1.fromJSON("{\"a\":\"1\",\"b\":{\"2\":2}}"); 41 | val = context1.eval("globalThis.val"); 42 | assert(val["a"].as() == 1); 43 | 44 | mc = context1.eval("mc"); 45 | } 46 | catch(qjs::exception e) 47 | { 48 | auto exc = e.get(); 49 | std::cerr << (std::string) exc << std::endl; 50 | if((bool) exc["stack"]) 51 | std::cerr << (std::string) exc["stack"] << std::endl; 52 | return 1; 53 | } 54 | try 55 | { 56 | glue(context2.addModule("MyModule")); 57 | context2.eval("import * as my from 'MyModule'; " "\n" 58 | "(new my.MyClass()).print_context(undefined);" "\n" 59 | ,"", JS_EVAL_TYPE_MODULE 60 | ); 61 | context2.global()["val"] = val; 62 | assert(val == context2.eval("globalThis.val")); 63 | 64 | context2.global()["mc"] = mc; 65 | // will print the first context even though we call it from second 66 | // see js_call_c_function 67 | context2.eval("mc.print_context(undefined)"); 68 | } 69 | catch(qjs::exception e) 70 | { 71 | auto exc = e.get(); 72 | std::cerr << (std::string) exc << std::endl; 73 | if((bool) exc["stack"]) 74 | std::cerr << (std::string) exc["stack"] << std::endl; 75 | return 1; 76 | } 77 | } -------------------------------------------------------------------------------- /test/value.cpp: -------------------------------------------------------------------------------- 1 | #include "quickjspp.hpp" 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | qjs::Runtime runtime; 8 | qjs::Context context(runtime); 9 | 10 | try 11 | { 12 | auto val1 = context.newValue(321); 13 | auto val2 = context.newValue(123); 14 | assert(val1 != val2); 15 | 16 | val1 = val2; 17 | assert(val1 == val2); 18 | 19 | val1 = context.newValue(123); 20 | assert(val1 == val2); 21 | 22 | val1 = std::move(val2); 23 | assert(val1.as() == "123"); 24 | 25 | assert((double) val1 == 123.0); 26 | 27 | val2 = context.newValue((std::string) "123"); 28 | assert(val1 != val2); 29 | 30 | context.global()["val1"] = val1; 31 | context.global()["val2"] = val2; 32 | 33 | 34 | assert((bool) context.eval("val1 !== val2")); 35 | assert((bool) context.eval("val1 == val2")); 36 | 37 | // 38 | 39 | val1 = context.newObject(); 40 | val1["a"] = "1"; 41 | val2 = context.newObject(); 42 | val2["a"] = "1"; 43 | 44 | assert(val1 != val2); 45 | 46 | context.global()["val1"] = val1; 47 | context.global()["val2"] = val2; 48 | 49 | assert((bool) context.eval("val1 !== val2")); 50 | assert((bool) context.eval("val1 != val2")); 51 | assert((bool)context.eval("JSON.stringify(val1) === JSON.stringify(val2)")); 52 | 53 | qjs::Value one = val1["a"]; 54 | assert((int)one == 1); 55 | 56 | assert(val1.toJSON() == val2.toJSON()); 57 | 58 | val1["b"] = context.newObject(); 59 | val1["b"][2] = 2; 60 | assert((int)val1["b"][2] == 2); 61 | 62 | assert(val1.toJSON() == context.fromJSON(val1.toJSON(JS_UNDEFINED, context.newValue("\t"))).toJSON()); 63 | 64 | assert(val1.toJSON() == "{\"a\":\"1\",\"b\":{\"2\":2}}"); 65 | 66 | assert(val1 == context.global()["val1"]); 67 | 68 | auto str = val1.toJSON(); 69 | assert(str == (std::string) context.eval(R"xxx( 70 | val1 = new Object(); 71 | val1["a"] = "1"; 72 | val1["b"] = new Object(); 73 | val1["b"][2] = 2; 74 | JSON.stringify(val1) 75 | )xxx")); 76 | } 77 | catch(qjs::exception) 78 | { 79 | auto exc = context.getException(); 80 | std::cerr << (exc.isError() ? "Error: " : "Throw: ") << (std::string) exc << std::endl; 81 | if((bool) exc["stack"]) 82 | std::cerr << (std::string) exc["stack"] << std::endl; 83 | return 1; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | QuickJSPP is QuickJS wrapper for C++. It allows you to easily embed Javascript engine into your program. 2 | 3 | QuickJS is a small and embeddable Javascript engine. It supports the ES2020 specification including modules, asynchronous generators and proxies. More info: 4 | 5 | # Example 6 | ```cpp 7 | #include "quickjspp.hpp" 8 | #include 9 | 10 | class MyClass 11 | { 12 | public: 13 | MyClass() {} 14 | MyClass(std::vector) {} 15 | 16 | double member_variable = 5.5; 17 | std::string member_function(const std::string& s) { return "Hello, " + s; } 18 | }; 19 | 20 | void println(qjs::rest args) { 21 | for (auto const & arg : args) std::cout << arg << " "; 22 | std::cout << "\n"; 23 | } 24 | 25 | int main() 26 | { 27 | qjs::Runtime runtime; 28 | qjs::Context context(runtime); 29 | try 30 | { 31 | // export classes as a module 32 | auto& module = context.addModule("MyModule"); 33 | module.function<&println>("println"); 34 | module.class_("MyClass") 35 | .constructor<>() 36 | .constructor>("MyClassA") 37 | .fun<&MyClass::member_variable>("member_variable") 38 | .fun<&MyClass::member_function>("member_function"); 39 | // import module 40 | context.eval(R"xxx( 41 | import * as my from 'MyModule'; 42 | globalThis.my = my; 43 | )xxx", "", JS_EVAL_TYPE_MODULE); 44 | // evaluate js code 45 | context.eval(R"xxx( 46 | let v1 = new my.MyClass(); 47 | v1.member_variable = 1; 48 | let v2 = new my.MyClassA([1,2,3]); 49 | function my_callback(str) { 50 | my.println("at callback:", v2.member_function(str)); 51 | } 52 | )xxx"); 53 | 54 | // callback 55 | auto cb = (std::function) context.eval("my_callback"); 56 | cb("world"); 57 | } 58 | catch(qjs::exception) 59 | { 60 | auto exc = context.getException(); 61 | std::cerr << (std::string) exc << std::endl; 62 | if((bool) exc["stack"]) 63 | std::cerr << (std::string) exc["stack"] << std::endl; 64 | return 1; 65 | } 66 | } 67 | ``` 68 | 69 | # Installation 70 | QuickJSPP is header-only - put quickjspp.hpp into your include search path. 71 | Compiler that supports C++17 or later is required. 72 | The program needs to be linked against QuickJS. 73 | Sample CMake project files are provided. 74 | 75 | # License 76 | QuickJSPP is licensed under [CC0](https://creativecommons.org/publicdomain/zero/1.0/). QuickJS is licensed under [MIT](https://opensource.org/licenses/MIT). 77 | -------------------------------------------------------------------------------- /quickjs/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 | -------------------------------------------------------------------------------- /quickjs/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 | -------------------------------------------------------------------------------- /qjs.cpp: -------------------------------------------------------------------------------- 1 | #include "quickjspp.hpp" 2 | #include "quickjs/quickjs-libc.h" 3 | 4 | #include 5 | #include 6 | 7 | /* also used to initialize the worker context */ 8 | static JSContext *JS_NewCustomContext(JSRuntime *rt) 9 | { 10 | JSContext *ctx; 11 | ctx = JS_NewContext(rt); 12 | if (!ctx) 13 | return NULL; 14 | 15 | /* system modules */ 16 | js_init_module_std(ctx, "std"); 17 | js_init_module_os(ctx, "os"); 18 | return ctx; 19 | } 20 | 21 | int main(int argc, char ** argv) 22 | { 23 | qjs::Runtime runtime; 24 | auto rt = runtime.rt; 25 | 26 | js_std_set_worker_new_context_func(JS_NewCustomContext); 27 | js_std_init_handlers(rt); 28 | 29 | /* loader for ES6 modules */ 30 | JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, NULL, NULL); 31 | 32 | qjs::Context context(JS_NewCustomContext(rt)); 33 | auto ctx = context.ctx; 34 | 35 | int flags = -1; 36 | int optind = 1; 37 | // load as ES6 module 38 | if(argv[optind] && (argv[optind] == std::string_view{"-m"} || argv[optind] == std::string_view{"--module"})) 39 | { 40 | flags = JS_EVAL_TYPE_MODULE; 41 | optind++; 42 | } 43 | // load as ES6 script 44 | else if(argv[optind] && argv[optind] == std::string_view{"--script"}) 45 | { 46 | flags = JS_EVAL_TYPE_GLOBAL; 47 | optind++; 48 | } 49 | 50 | js_std_add_helpers(ctx, argc - optind, argv + optind); 51 | 52 | /* make 'std' and 'os' visible to non module code */ 53 | context.eval(R"xxx( 54 | import * as std from 'std'; 55 | import * as os from 'os'; 56 | globalThis.std = std; 57 | globalThis.os = os; 58 | )xxx", "", JS_EVAL_TYPE_MODULE); 59 | 60 | 61 | try 62 | { 63 | if(auto filename = argv[optind]) 64 | { 65 | auto buf = qjs::detail::readFile(filename); 66 | if (!buf) 67 | throw std::runtime_error{std::string{"can't read file: "} + filename}; 68 | 69 | // autodetect file type 70 | if(flags == -1) 71 | flags = JS_DetectModule(buf->data(), buf->size()) ? JS_EVAL_TYPE_MODULE : JS_EVAL_TYPE_GLOBAL; 72 | 73 | context.eval(*buf, filename, flags); 74 | } 75 | else 76 | { 77 | std::cout << argv[0] << " [--module|--script] " << std::endl; 78 | js_std_free_handlers(rt); 79 | return 1; 80 | } 81 | } 82 | catch(qjs::exception & e) 83 | { 84 | auto exc = e.get(); 85 | std::cerr << (exc.isError() ? "Error: " : "Throw: ") << (std::string)exc << std::endl; 86 | if((bool)exc["stack"]) 87 | std::cerr << (std::string)exc["stack"] << std::endl; 88 | 89 | js_std_free_handlers(rt); 90 | return 1; 91 | } 92 | 93 | js_std_loop(ctx); 94 | 95 | js_std_free_handlers(rt); 96 | 97 | return 0; 98 | 99 | } 100 | -------------------------------------------------------------------------------- /test/module_loader.cpp: -------------------------------------------------------------------------------- 1 | #include "quickjspp.hpp" 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | qjs::Runtime runtime; 8 | qjs::Context context(runtime); 9 | 10 | std::unordered_map files = { 11 | { 12 | "some_module.js", 13 | R"xxx( 14 | import "folder/file1.js" 15 | log(import.meta.url); 16 | )xxx" 17 | }, 18 | { 19 | "folder/file1.js", 20 | R"xxx( 21 | import "./file2.js" 22 | log(import.meta.url); 23 | )xxx" 24 | }, 25 | { 26 | "folder/file2.js", 27 | R"xxx( 28 | import "http://localhost/script1.js"; 29 | log(import.meta.url); 30 | )xxx" 31 | }, 32 | { 33 | "http://localhost/script1.js", 34 | R"xxx( 35 | import "./script2.js"; 36 | log(import.meta.url); 37 | )xxx" 38 | }, 39 | { 40 | "http://localhost/script2.js", 41 | R"xxx( 42 | log(import.meta.url); 43 | )xxx" 44 | }, 45 | }; 46 | 47 | auto mock_module_loader = [&files](std::string_view filename) -> qjs::Context::ModuleData { 48 | if (files.count(filename)) return { qjs::detail::toUri(filename), files.at(filename) }; 49 | return {}; 50 | }; 51 | 52 | // Test a failing import with the default moduleLoader 53 | try 54 | { 55 | context.eval(R"xxx( 56 | import "./invalid_module.js"; 57 | )xxx", "", JS_EVAL_TYPE_MODULE); 58 | assert(false && "module import should have failed"); 59 | } 60 | catch(qjs::exception e) 61 | { 62 | auto exc = e.get(); 63 | assert(exc.isError() && "Exception should be a JS error"); 64 | assert((std::string)exc == "ReferenceError: could not load module filename 'invalid_module.js'"); 65 | } 66 | 67 | context.moduleLoader = mock_module_loader; 68 | context.global()["log"] = [](std::string_view s) { 69 | std::cout << s << std::endl; 70 | }; 71 | 72 | // Test a successful import with the mock moduleLoader 73 | // It pretends to import things from the filesystem and from URLs 74 | context.eval(R"xxx( 75 | import "./some_module.js"; 76 | )xxx", "", JS_EVAL_TYPE_MODULE); 77 | 78 | // Test a failing import with the mock moduleLoader 79 | try 80 | { 81 | context.eval(R"xxx( 82 | import "./invalid_module.js"; 83 | )xxx", "", JS_EVAL_TYPE_MODULE); 84 | assert(false && "module import should have failed"); 85 | } 86 | catch(qjs::exception e) 87 | { 88 | auto exc = e.get(); 89 | assert(exc.isError() && "Exception should be a JS error"); 90 | assert((std::string)exc == "ReferenceError: could not load module filename 'invalid_module.js'"); 91 | } 92 | 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /quickjs/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 | -------------------------------------------------------------------------------- /quickjs/patches/2025-04-26-unhandled_rejection.patch: -------------------------------------------------------------------------------- 1 | diff --git a/quickjs/quickjs.c b/quickjs/quickjs.c 2 | index 325c6dd..0535169 100644 3 | --- a/quickjs/quickjs.c 4 | +++ b/quickjs/quickjs.c 5 | @@ -278,6 +278,9 @@ struct JSRuntime { 6 | JSHostPromiseRejectionTracker *host_promise_rejection_tracker; 7 | void *host_promise_rejection_tracker_opaque; 8 | 9 | + JSHostPromiseRejectionTracker *host_unhandled_promise_rejection_tracker; 10 | + void *host_unhandled_promise_rejection_tracker_opaque; 11 | + 12 | struct list_head job_list; /* list of JSJobEntry.link */ 13 | 14 | JSModuleNormalizeFunc *module_normalize_func; 15 | @@ -49246,6 +49249,7 @@ typedef struct JSPromiseData { 16 | struct list_head promise_reactions[2]; 17 | BOOL is_handled; /* Note: only useful to debug */ 18 | JSValue promise_result; 19 | + JSContext * ctx; 20 | } JSPromiseData; 21 | 22 | typedef struct JSPromiseFunctionDataResolved { 23 | @@ -49342,6 +49346,14 @@ void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, 24 | rt->host_promise_rejection_tracker_opaque = opaque; 25 | } 26 | 27 | +void JS_SetHostUnhandledPromiseRejectionTracker(JSRuntime *rt, 28 | + JSHostPromiseRejectionTracker *cb, 29 | + void *opaque) 30 | +{ 31 | + rt->host_unhandled_promise_rejection_tracker = cb; 32 | + rt->host_unhandled_promise_rejection_tracker_opaque = opaque; 33 | +} 34 | + 35 | static void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise, 36 | JSValueConst value, BOOL is_reject) 37 | { 38 | @@ -49546,6 +49558,14 @@ static void js_promise_finalizer(JSRuntime *rt, JSValue val) 39 | 40 | if (!s) 41 | return; 42 | + 43 | + if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) { 44 | + if (rt->host_unhandled_promise_rejection_tracker) { 45 | + rt->host_unhandled_promise_rejection_tracker(s->ctx, val, s->promise_result, FALSE, 46 | + rt->host_unhandled_promise_rejection_tracker_opaque); 47 | + } 48 | + } 49 | + 50 | for(i = 0; i < 2; i++) { 51 | list_for_each_safe(el, el1, &s->promise_reactions[i]) { 52 | JSPromiseReactionData *rd = 53 | @@ -49596,6 +49616,7 @@ static JSValue js_promise_constructor(JSContext *ctx, JSValueConst new_target, 54 | s = js_mallocz(ctx, sizeof(*s)); 55 | if (!s) 56 | goto fail; 57 | + s->ctx = ctx; 58 | s->promise_state = JS_PROMISE_PENDING; 59 | s->is_handled = FALSE; 60 | for(i = 0; i < 2; i++) 61 | diff --git a/quickjs/quickjs.h b/quickjs/quickjs.h 62 | index 4570c6d..80aacc4 100644 63 | --- a/quickjs/quickjs.h 64 | +++ b/quickjs/quickjs.h 65 | @@ -912,6 +912,7 @@ typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise, 66 | JSValueConst reason, 67 | JS_BOOL is_handled, void *opaque); 68 | void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTracker *cb, void *opaque); 69 | +void JS_SetHostUnhandledPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTracker *cb, void *opaque); 70 | 71 | /* return != 0 if the JS code needs to be interrupted */ 72 | typedef int JSInterruptHandler(JSRuntime *rt, void *opaque); 73 | -------------------------------------------------------------------------------- /test/variant.cpp: -------------------------------------------------------------------------------- 1 | #include "quickjspp.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | struct A {}; 7 | 8 | struct B {}; 9 | 10 | using var = std::variant, std::shared_ptr, std::shared_ptr>; 11 | 12 | 13 | auto f(var v1, const var& /*v2*/) -> var 14 | { 15 | return std::visit([](auto&& v) -> var { 16 | using T = std::decay_t; 17 | if constexpr (std::is_same_v>) 18 | return std::make_shared(); 19 | else if constexpr (std::is_same_v>) 20 | return std::make_shared(); 21 | else if constexpr (std::is_same_v>) 22 | { 23 | v.push_back(0); 24 | return v; 25 | } else 26 | return v + v; 27 | }, v1); 28 | } 29 | 30 | using var2 = std::variant>>; 31 | 32 | 33 | auto f2(var2 v2) -> var 34 | { 35 | if(auto *v = std::get_if(&v2)) 36 | return *v; 37 | if(auto *vec = std::get_if>>(&v2)) 38 | return (*vec)[0].first; 39 | std::abort(); 40 | } 41 | 42 | void assert_(bool condition) 43 | { 44 | if(!condition) throw std::runtime_error("assertion failed"); 45 | } 46 | 47 | static void qjs_glue(qjs::Context::Module& m) 48 | { 49 | m.class_<::A>("A") 50 | .constructor<>() 51 | // implicit: .constructor<::A const &>() 52 | ; 53 | 54 | m.class_<::B>("B") 55 | .constructor<>() 56 | // implicit: .constructor<::B const &>() 57 | ; 58 | m.function<&::assert_>("assert"); // (bool) 59 | m.function<&::f>("f"); // (::var, ::var const &) 60 | m.function<&::f2>("f2"); 61 | } // qjs_glue 62 | 63 | 64 | int main() 65 | { 66 | qjs::Runtime runtime; 67 | qjs::Context context(runtime); 68 | 69 | try 70 | { 71 | // export classes as a module 72 | auto& module = context.addModule("MyModule"); 73 | qjs_glue(module); 74 | // import module 75 | context.eval("import * as my from 'MyModule'; globalThis.my = my;", "", JS_EVAL_TYPE_MODULE); 76 | // evaluate js code 77 | context.eval("let x = 1;" 78 | "my.assert(my.f(x, x) === 2);" 79 | "x = 'aaa';" 80 | "my.assert(my.f(x, x) === 'aaaaaa');" 81 | "x = 3.14;" 82 | "my.assert(my.f(x, x) === 6.28);" 83 | "x = [3,2,1];" 84 | "my.assert(JSON.stringify(my.f(x, x)) === '[3,2,1,0]');" 85 | "x = new my.A();" 86 | "my.assert(my.f(x, x) instanceof my.B);" 87 | "x = new my.B();" 88 | "my.assert(my.f(x, x) instanceof my.A);" 89 | "my.assert(my.f2(x) instanceof my.B);" 90 | "my.assert(my.f2([[x,x]]) instanceof my.B);" 91 | "my.assert(my.f2([[my.f(x,x),x]]) instanceof my.A);" 92 | ); 93 | } 94 | catch(qjs::exception) 95 | { 96 | auto exc = context.getException(); 97 | std::cerr << (std::string) exc << std::endl; 98 | if((bool) exc["stack"]) 99 | std::cerr << (std::string) exc["stack"] << std::endl; 100 | return 1; 101 | } 102 | 103 | } -------------------------------------------------------------------------------- /quickjs/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 | -------------------------------------------------------------------------------- /test/function_call.cpp: -------------------------------------------------------------------------------- 1 | #include "quickjs/quickjs.h" 2 | #include "quickjspp.hpp" 3 | #include 4 | #include 5 | 6 | int test_not_enough_arguments(qjs::Context & ctx) { 7 | std::string msg; 8 | 9 | ctx.global()["test_fcn"] = [](int a, int b, int c) { 10 | return a + b + c; 11 | }; 12 | 13 | try 14 | { 15 | ctx.eval(R"xxx( 16 | function assert(b, str = "FAIL") { 17 | if (b) { 18 | return; 19 | } else { 20 | throw Error("assertion failed: " + str); 21 | } 22 | } 23 | 24 | function assert_eq(a, b, str = "") { 25 | assert(a === b, `${JSON.stringify(a)} should be equal to ${JSON.stringify(b)}. ${str}`); 26 | } 27 | 28 | try { 29 | test_fcn(1); 30 | assert(false); 31 | } catch (err) { 32 | assert(err instanceof TypeError); 33 | assert_eq(err.message, 'Expected at least 3 arguments but received 1'); 34 | } 35 | )xxx"); 36 | } 37 | catch(qjs::exception) 38 | { 39 | auto exc = ctx.getException(); 40 | std::cerr << (std::string) exc << std::endl; 41 | if((bool) exc["stack"]) 42 | std::cerr << (std::string) exc["stack"] << std::endl; 43 | return 1; 44 | } 45 | 46 | return 0; 47 | } 48 | 49 | int test_call_with_rest_parameters(qjs::Context & ctx) { 50 | ctx.global()["test_fcn_rest"] = [](int a, qjs::rest args) { 51 | for (auto arg : args) { 52 | a += arg; 53 | } 54 | return a; 55 | }; 56 | 57 | ctx.global()["test_fcn_vec"] = [](int a, std::vector args) { 58 | for (auto arg : args) { 59 | a += arg; 60 | } 61 | return a; 62 | }; 63 | 64 | try 65 | { 66 | ctx.eval(R"xxx( 67 | function assert(b, str = "FAIL") { 68 | if (b) { 69 | return; 70 | } else { 71 | throw Error("assertion failed: " + str); 72 | } 73 | } 74 | 75 | function assert_eq(a, b, str = "") { 76 | assert(a === b, `${JSON.stringify(a)} should be equal to ${JSON.stringify(b)}. ${str}`); 77 | } 78 | 79 | function assert_throw(g, str = "") { 80 | try { 81 | f(); 82 | assert(false, `Expression should have thrown`) 83 | } catch (e) { 84 | } 85 | } 86 | 87 | assert_eq(test_fcn_rest(1, 2, 3, 4), 10); 88 | assert_eq(test_fcn_vec(1, [2, 3, 4]), 10); 89 | 90 | assert_throw(() => test_fcn_rest(1, [2, 3, 4])); 91 | assert_throw(() => test_fcn_vec(1, 2, 3, 4)); 92 | )xxx"); 93 | } 94 | catch(qjs::exception) 95 | { 96 | auto exc = ctx.getException(); 97 | std::cerr << (std::string) exc << std::endl; 98 | if((bool) exc["stack"]) 99 | std::cerr << (std::string) exc["stack"] << std::endl; 100 | return 1; 101 | } 102 | 103 | return 0; 104 | } 105 | 106 | int main() 107 | { 108 | qjs::Runtime runtime; 109 | qjs::Context context(runtime); 110 | 111 | int ret = 0; 112 | ret |= test_not_enough_arguments(context); 113 | ret |= test_call_with_rest_parameters(context); 114 | 115 | return ret; 116 | } -------------------------------------------------------------------------------- /quickjs/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 | -------------------------------------------------------------------------------- /binding-generator/generator.py: -------------------------------------------------------------------------------- 1 | 2 | # python3 generator.py -std=c++1z ../main.cpp 3 | # python3, castxml and pygccxml should be installed 4 | 5 | import os 6 | import sys 7 | 8 | # Find out the file location within the sources tree 9 | this_module_dir_path = os.path.abspath( 10 | os.path.dirname(sys.modules[__name__].__file__)) 11 | # Add pygccxml package to Python path 12 | #sys.path.append(os.path.join(this_module_dir_path, '..', '..')) 13 | 14 | 15 | from pygccxml import parser # nopep8 16 | from pygccxml import declarations # nopep8 17 | from pygccxml import utils # nopep8 18 | 19 | # Find out the xml generator (gccxml or castxml) 20 | generator_path, generator_name = utils.find_xml_generator() 21 | 22 | flags = filter(lambda x: x.startswith("-"), sys.argv[1:]) 23 | 24 | # Configure the xml generator 25 | config = parser.xml_generator_configuration_t( 26 | xml_generator_path=generator_path, 27 | xml_generator=generator_name, 28 | cflags=" ".join(flags), 29 | # start_with_declarations="test", 30 | #compiler="gcc", 31 | ) 32 | 33 | # Parsing source file 34 | 35 | filenames = list(filter(lambda x: not x.startswith("-"), sys.argv[1:])) 36 | full_filenames = [os.path.abspath(filename) for filename in filenames ] 37 | 38 | decls = parser.parse(full_filenames, 39 | config, 40 | compilation_mode=parser.COMPILATION_MODE.ALL_AT_ONCE 41 | 42 | ) 43 | global_ns = declarations.get_global_namespace(decls) 44 | 45 | write_hdrs = True 46 | 47 | if write_hdrs: 48 | for filename in filenames: 49 | print('#include "%s"' % filename) 50 | 51 | 52 | def get_prefix(member, duplicates): 53 | p = [] 54 | try: 55 | if member.name in duplicates: 56 | p.append("overload") 57 | if member.is_artificial: 58 | p.append("implicit") 59 | if member.access_type != "public": 60 | p.append(member.access_type) 61 | except AttributeError: 62 | pass 63 | if p == []: 64 | duplicates.append(member.name) 65 | return "" 66 | return "// " + ", ".join(p) + ": " 67 | 68 | 69 | def get_arg_types(fn): 70 | return ", ".join([x.decl_string for x in fn.argument_types]) 71 | 72 | def get_addr(fn): 73 | #return "static_cast<" + fn.decl_string + ">(&" + declarations.declaration_utils.full_name(fn) + ")" 74 | return "&" + declarations.declaration_utils.full_name(fn) 75 | 76 | 77 | 78 | write_fn = True 79 | 80 | if write_fn: 81 | print('void qjs_glue(qjs::Context::Module& m) {') 82 | 83 | dump_all = False 84 | 85 | # print free functions 86 | free_dups = [] 87 | for fn in global_ns.free_functions(allow_empty=True): 88 | if not dump_all and not fn.location.file_name in full_filenames: 89 | continue 90 | 91 | print('%sm.function<%s>("%s"); // (%s)' % (get_prefix(fn, free_dups), get_addr(fn), fn.name, get_arg_types(fn))) 92 | 93 | 94 | visited = [] 95 | 96 | def dump_class(class_): 97 | if class_ in visited: 98 | return 99 | visited.append(class_) 100 | duplicates = [] 101 | print('m.class_<%s>("%s")' % (declarations.declaration_utils.full_name(class_), class_.name)) 102 | # print('\tbase classes : ', repr([ 103 | for base in class_.bases: 104 | print('\t//.base<%s>()' % declarations.declaration_utils.full_name(base.related_class)); 105 | for fn in class_.constructors(allow_empty=True): 106 | print('\t%s.constructor<%s>()' % (get_prefix(fn, duplicates), get_arg_types(fn))) 107 | for fn in class_.member_functions(allow_empty=True): 108 | print('\t%s.fun<%s>("%s") // (%s)' % (get_prefix(fn, duplicates), get_addr(fn), fn.name, get_arg_types(fn))) 109 | for fn in class_.variables(allow_empty=True): 110 | print('\t%s.fun<%s>("%s") // %s' % (get_prefix(fn, duplicates), get_addr(fn), fn.name, fn.decl_type.decl_string)) 111 | print(';\n') 112 | 113 | # Print all classes 114 | for class_ in global_ns.classes(): 115 | if not dump_all and not class_.location.file_name in full_filenames: 116 | continue 117 | dump_class(class_) 118 | 119 | if write_fn: 120 | print('} // qjs_glue') 121 | -------------------------------------------------------------------------------- /test/exception.cpp: -------------------------------------------------------------------------------- 1 | #include "quickjspp.hpp" 2 | #include 3 | #include 4 | 5 | struct A{}; 6 | 7 | struct B { 8 | B() { 9 | throw std::runtime_error("constructor error"); 10 | } 11 | B(int) {} 12 | void a_method() { 13 | throw std::runtime_error("method error"); 14 | } 15 | }; 16 | 17 | int main() 18 | { 19 | qjs::Runtime runtime; 20 | qjs::Context context(runtime); 21 | context.global()["println"] = [](const std::string& s) { std::cout << s << std::endl; }; 22 | 23 | context.registerClass("A"); 24 | context.registerClass("A"); 25 | 26 | auto& testMod = context.addModule("test"); 27 | 28 | testMod.class_("B") 29 | .constructor<>("B") 30 | .constructor("B_int") 31 | .fun<&B::a_method>("a_method"); 32 | 33 | try 34 | { 35 | auto obj = context.eval("Symbol.toPrimitive"); 36 | std::cout << static_cast(obj) << std::endl; 37 | assert(false); 38 | } 39 | catch(qjs::exception) 40 | { 41 | auto exc = context.getException(); 42 | std::cerr << (exc.isError() ? "Error: " : "Throw: ") << (std::string)exc << std::endl; 43 | if((bool)exc["stack"]) 44 | std::cerr << (std::string)exc["stack"] << std::endl; 45 | assert(exc.isError() && (std::string) exc == "TypeError: cannot convert symbol to number"); 46 | } 47 | 48 | try 49 | { 50 | auto f = (std::function) context.eval("(function() { +Symbol.toPrimitive })"); 51 | f(); 52 | assert(false); 53 | } 54 | catch(qjs::exception) 55 | { 56 | auto exc = context.getException(); 57 | std::cerr << (exc.isError() ? "Error: " : "Throw: ") << (std::string)exc << std::endl; 58 | if((bool)exc["stack"]) 59 | std::cerr << (std::string)exc["stack"] << std::endl; 60 | assert(exc.isError() && (std::string) exc == "TypeError: cannot convert symbol to number"); 61 | } 62 | 63 | try 64 | { 65 | qjs::Value function = context.eval("() => { let a = b; }", ""); 66 | auto native = function.as>(); 67 | qjs::Value result = native(); 68 | assert(false); 69 | } 70 | catch(qjs::exception) 71 | { 72 | auto exc = context.getException(); 73 | std::cerr << (exc.isError() ? "Error: " : "Throw: ") << (std::string)exc << std::endl; 74 | if((bool)exc["stack"]) 75 | std::cerr << (std::string)exc["stack"] << std::endl; 76 | assert(exc.isError() && (std::string) exc == "ReferenceError: 'b' is not defined"); 77 | } 78 | 79 | // test the `wrap_call` case 80 | try 81 | { 82 | qjs::Value caller = context.eval("(f) => f();", ""); 83 | caller.as)>>()([](){ 84 | throw std::runtime_error("some error"); 85 | }); 86 | assert(false); 87 | } 88 | catch(qjs::exception) 89 | { 90 | auto exc = context.getException(); 91 | std::cerr << (exc.isError() ? "Error: " : "Throw: ") << (std::string)exc << std::endl; 92 | if((bool)exc["stack"]) 93 | std::cerr << (std::string)exc["stack"] << std::endl; 94 | assert(exc.isError() && (std::string) exc == "InternalError: some error"); 95 | } 96 | 97 | // test the `ctor_wrapper` case 98 | try 99 | { 100 | qjs::Value caller = context.eval(R"xxx( 101 | import { B } from "test"; 102 | const b = new B(); 103 | )xxx", "", JS_EVAL_TYPE_MODULE); 104 | assert(false); 105 | } 106 | catch(qjs::exception) 107 | { 108 | auto exc = context.getException(); 109 | std::cerr << (exc.isError() ? "Error: " : "Throw: ") << (std::string)exc << std::endl; 110 | if((bool)exc["stack"]) 111 | std::cerr << (std::string)exc["stack"] << std::endl; 112 | assert(exc.isError() && (std::string) exc == "InternalError: constructor error"); 113 | } 114 | 115 | // test the `wrap_this_call` case 116 | try 117 | { 118 | qjs::Value caller = context.eval(R"xxx( 119 | import { B_int } from "test"; 120 | const b = new B_int(123); 121 | b.a_method(); 122 | )xxx", "", JS_EVAL_TYPE_MODULE); 123 | assert(false); 124 | } 125 | catch(qjs::exception) 126 | { 127 | auto exc = context.getException(); 128 | std::cerr << (exc.isError() ? "Error: " : "Throw: ") << (std::string)exc << std::endl; 129 | if((bool)exc["stack"]) 130 | std::cerr << (std::string)exc["stack"] << std::endl; 131 | assert(exc.isError() && (std::string) exc == "InternalError: method error"); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /.github/workflows/cxx.yml: -------------------------------------------------------------------------------- 1 | name: CMake C/C++ CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | fail-fast: false 10 | matrix: 11 | compiler: [linux-gcc,linux-clang,linux-gcc8,linux-gcc10,linux-gcc-ubsan,linux-gcc-asan,linux-gcc-32,linux-gcc-x32,linux-clang11,linux-clang12,macos-clang] 12 | build_type: [Debug] 13 | include: 14 | - compiler: linux-gcc 15 | os: ubuntu-latest 16 | 17 | - compiler: linux-clang 18 | os: ubuntu-latest 19 | cmake_opts: -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ 20 | 21 | - compiler: linux-gcc8 22 | os: ubuntu-18.04 23 | preconfigure: sudo apt-get update && sudo apt-get install -y gcc-8 g++-8 24 | cmake_opts: -DCMAKE_C_COMPILER=gcc-8 -DCMAKE_CXX_COMPILER=g++-8 -DCMAKE_REQUIRED_LIBRARIES=stdc++fs 25 | 26 | - compiler: linux-gcc10 27 | os: ubuntu-20.04 28 | preconfigure: sudo apt-get update && sudo apt-get install -y gcc-10 g++-10 29 | cmake_opts: -DCMAKE_C_COMPILER=gcc-10 -DCMAKE_CXX_COMPILER=g++-10 30 | 31 | - compiler: linux-gcc-ubsan 32 | os: ubuntu-latest 33 | cflags: -fsanitize=undefined 34 | 35 | - compiler: linux-gcc-asan 36 | os: ubuntu-latest 37 | cflags: -fsanitize=address -fsanitize-address-use-after-scope 38 | 39 | - compiler: linux-gcc-32 40 | os: ubuntu-latest 41 | preconfigure: sudo apt-get update && sudo apt-get install gcc-multilib g++-multilib 42 | cflags: -m32 43 | 44 | - compiler: linux-gcc-x32 45 | os: ubuntu-latest 46 | preconfigure: sudo apt-get update && sudo apt-get install gcc-multilib g++-multilib 47 | cflags: -mx32 48 | 49 | - compiler: linux-clang11 50 | os: ubuntu-20.04 51 | preconfigure: sudo apt-get update && sudo apt-get install -y clang-11 libc++-11-dev libc++abi-11-dev 52 | cmake_opts: -DCMAKE_C_COMPILER=clang-11 -DCMAKE_CXX_COMPILER=clang++-11 53 | cflags: -stdlib=libc++ 54 | 55 | - compiler: linux-clang12 56 | os: ubuntu-20.04 57 | preconfigure: sudo apt-get update && sudo apt-get install -y clang-12 libc++-12-dev libc++abi-12-dev 58 | cmake_opts: -DCMAKE_C_COMPILER=clang-12 -DCMAKE_CXX_COMPILER=clang++-12 59 | cflags: -stdlib=libc++ 60 | 61 | - compiler: macos-clang 62 | os: macos-latest 63 | 64 | steps: 65 | - uses: actions/checkout@v2 66 | with: 67 | submodules: recursive 68 | - name: preconfigure 69 | run: ${{ matrix.preconfigure }} 70 | - name: configure 71 | run: cmake -S . -B build_dir -Wdev -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCMAKE_C_FLAGS="${{ matrix.cflags }}" -DCMAKE_CXX_FLAGS="${{ matrix.cflags }}" -DCMAKE_EXE_LINKER_FLAGS="${{ matrix.cflags }}" ${{ matrix.cmake_opts }} 72 | - name: build 73 | run: cmake --build build_dir --verbose 74 | - name: test 75 | run: ctest --extra-verbose 76 | working-directory: build_dir 77 | env: 78 | # extra options for address sanitizer 79 | ASAN_OPTIONS: strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1 80 | 81 | build_windows: 82 | runs-on: ${{ matrix.os }} 83 | strategy: 84 | fail-fast: false 85 | matrix: 86 | compiler: [windows-gcc] 87 | build_type: [Debug] 88 | include: 89 | - compiler: windows-gcc 90 | os: windows-2019 91 | cmake_opts: -G "Ninja" -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ 92 | 93 | # - compiler: windows-msvs # not supported 94 | # os: windows-latest 95 | 96 | defaults: 97 | run: 98 | shell: msys2 {0} 99 | 100 | steps: 101 | - uses: actions/checkout@v2 102 | with: 103 | submodules: recursive 104 | - uses: msys2/setup-msys2@v2 105 | with: 106 | msystem: MINGW64 107 | update: true 108 | install: git cmake ninja mingw-w64-x86_64-toolchain mingw-w64-x86_64-dlfcn 109 | - name: preconfigure 110 | run: ${{ matrix.preconfigure }} 111 | - name: configure 112 | run: cmake -S . -B build_dir -Wdev -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCMAKE_C_FLAGS="${{ matrix.cflags }}" -DCMAKE_CXX_FLAGS="${{ matrix.cflags }}" -DCMAKE_EXE_LINKER_FLAGS="${{ matrix.cflags }}" ${{ matrix.cmake_opts }} 113 | - name: build 114 | run: cmake --build build_dir --verbose 115 | - name: test 116 | run: ctest --extra-verbose 117 | working-directory: build_dir 118 | env: 119 | # extra options for address sanitizer 120 | ASAN_OPTIONS: strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1 -------------------------------------------------------------------------------- /quickjs/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 | -------------------------------------------------------------------------------- /test/class.cpp: -------------------------------------------------------------------------------- 1 | #include "quickjspp.hpp" 2 | #include "quickjs/quickjs-libc.h" 3 | #include 4 | 5 | 6 | #define TYPES bool, int32_t, double, std::shared_ptr, const std::shared_ptr&, std::string, const std::string& 7 | 8 | class base_test 9 | { 10 | public: 11 | std::vector> base_field; 12 | 13 | int base_method(int x) 14 | { 15 | std::swap(x, base_field[0][0]); 16 | return x; 17 | } 18 | }; 19 | 20 | class test : public base_test 21 | { 22 | public: 23 | bool b; 24 | mutable int32_t i; 25 | double d = 7.; 26 | std::shared_ptr spt; 27 | std::string s; 28 | 29 | test(int32_t i, TYPES) : i(i) 30 | { printf("ctor!\n"); } 31 | 32 | test(int32_t i) : i(i) 33 | { printf("ctor %d!\n", i); } 34 | 35 | test(const test&) = delete; 36 | 37 | ~test() 38 | { printf("dtor!\n"); } 39 | 40 | int32_t fi(TYPES) const { i++; return i; } 41 | bool fb(TYPES) { i++; return b; } 42 | double fd(TYPES) const { i++; return d; } 43 | const std::shared_ptr& fspt(TYPES) { i++; return spt; } 44 | const std::string& fs(TYPES) { i++; return s; } 45 | void f(TYPES) { i++; } 46 | 47 | double get_d() { i++; return d; } 48 | double set_d(double new_d) { i++; d = new_d; return d; } 49 | 50 | 51 | static void fstatic(TYPES) {} 52 | static bool bstatic; 53 | }; 54 | bool test::bstatic = true; 55 | 56 | void f(TYPES) {} 57 | 58 | void qjs_glue(qjs::Context::Module& m) { 59 | m.function<&::f>("f"); // (bool, ::int32_t, double, ::std::shared_ptr, ::std::shared_ptr const &, ::std::string, ::std::string const &) 60 | m.class_<::base_test>("base_test") 61 | // implicit: .constructor<::base_test const &>() 62 | .constructor<>() 63 | .fun<&::base_test::base_method>("base_method") // (double) 64 | .fun<&::base_test::base_field>("base_field") // double 65 | ; 66 | 67 | m.class_<::test>("test") 68 | //.base<::base_test>() 69 | .constructor<::int32_t, bool, ::int32_t, double, ::qjs::shared_ptr, ::qjs::shared_ptr const &, ::std::string, ::std::string const &>("Test") 70 | .static_fun<&::test::fstatic>("fstatic") // (bool, ::int32_t, double, ::std::shared_ptr, ::std::shared_ptrconst &, ::std::string, ::std::string const &) 71 | .static_fun<&::test::bstatic>("bstatic") // bool 72 | .constructor<::int32_t>("TestSimple") 73 | .fun<&::test::fi>("fi") // (bool, ::int32_t, double, ::std::shared_ptr, ::std::shared_ptr const &, ::std::string, ::std::string const &) 74 | .fun<&::test::fb>("fb") // (bool, ::int32_t, double, ::std::shared_ptr, ::std::shared_ptr const &, ::std::string, ::std::string const &) 75 | .fun<&::test::fd>("fd") // (bool, ::int32_t, double, ::std::shared_ptr, ::std::shared_ptr const &, ::std::string, ::std::string const &) 76 | .fun<&::test::fspt>("fspt") // (bool, ::int32_t, double, ::std::shared_ptr, ::std::shared_ptr const&, ::std::string, ::std::string const &) 77 | .fun<&::test::fs>("fs") // (bool, ::int32_t, double, ::std::shared_ptr, ::std::shared_ptr const &, ::std::string, ::std::string const &) 78 | .fun<&::test::f>("f") // (bool, ::int32_t, double, ::std::shared_ptr, ::std::shared_ptr const &, ::std::string, ::std::string const &) 79 | .fun<&::test::b>("b") // bool 80 | .fun<&::test::i>("i") // ::int32_t 81 | .fun<&::test::d>("d") // double 82 | .fun<&::test::spt>("spt") // ::std::shared_ptr 83 | .fun<&::test::s>("s") // ::std::string 84 | .property<&test::get_d, &test::set_d>("property_rw") 85 | .property<&test::get_d>("property_ro") 86 | ; 87 | } // qjs_glue 88 | 89 | int main() 90 | { 91 | JSRuntime * rt; 92 | JSContext * ctx; 93 | using namespace qjs; 94 | 95 | Runtime runtime; 96 | rt = runtime.rt; 97 | 98 | Context context(runtime); 99 | ctx = context.ctx; 100 | 101 | try 102 | { 103 | qjs_glue(context.addModule("test")); 104 | 105 | js_std_init_handlers(rt); 106 | /* loader for ES6 modules */ 107 | JS_SetModuleLoaderFunc2(rt, nullptr, js_module_loader, nullptr, nullptr); 108 | js_std_add_helpers(ctx, 0, nullptr); 109 | 110 | /* system modules */ 111 | js_init_module_std(ctx, "std"); 112 | js_init_module_os(ctx, "os"); 113 | 114 | /* make 'std' and 'os' visible to non module code */ 115 | const char * str = "import * as std from 'std';\n" 116 | "import * as os from 'os';\n" 117 | "import * as test from 'test';\n" 118 | "globalThis.std = std;\n" 119 | "globalThis.test = test;\n" 120 | "globalThis.os = os;\n"; 121 | context.eval(str, "", JS_EVAL_TYPE_MODULE); 122 | 123 | 124 | context.global()["assert"] = [](bool t) { if(!t) std::exit(2); }; 125 | 126 | 127 | auto xxx = context.eval("\"use strict\";" 128 | "var b = new test.base_test();" 129 | "b.base_field = [[5],[1,2,3,4],[6]];" 130 | "assert(b.base_field[1][3] === 4);" 131 | "assert(b.base_method(123) === 5);" 132 | "assert(b.base_field[0][0] === 123);" 133 | 134 | "var t = new test.TestSimple(12);" 135 | "var q = new test.Test(13, t.vb, t.vi, t.vd, t, t, t.vs, t.vs);" 136 | "q.b = true;" 137 | "q.d = 456.789;" 138 | "q.s = \"STRING\";" 139 | "q.spt = t;" 140 | //"q.base_field = 105.5;" 141 | "assert(q.b === q.fb(t.vb, t.vi, t.vd, t, t, t.vs, \"test\"));" 142 | "assert(q.d === q.fd(t.vb, t.vi, t.vd, t, t, t.vs, \"test\"));" 143 | "assert(q.s === q.fs(t.vb, t.vi, t.vd, t, t, \"test\", t.vs));" 144 | //"assert(105.5 === q.base_method(5.1));" 145 | //"assert(5.1 === q.base_field);" 146 | "assert(q.spt !== q.fspt(t.vb, t.vi, t.vd, t, t, t.vs, \"test\"));" // different objects 147 | "q.fi(t.vb, t.vi, t.vd, t, t, t.vs, \"test\")"); 148 | assert((int)xxx == 18); 149 | auto yyy = context.eval("q.fi.bind(t)(t.vb, t.vi, t.vd, t, t, t.vs, \"test\")"); 150 | assert((int)yyy == 13); 151 | 152 | auto f = context.eval("q.fi.bind(q)").as>(); 153 | int zzz = f(false, 1, 0., context.eval("q").as>(), 154 | context.eval("t").as>(), "test string", std::string{"test"}); 155 | assert(zzz == 19); 156 | 157 | zzz = (int)context.eval("q.property_rw = q.property_ro - q.property_rw + 1;" 158 | "assert(q.property_ro === 1);" 159 | "q.i" 160 | ); 161 | assert(zzz == 23); 162 | 163 | assert((bool)context.eval("test.Test.bstatic === true")); 164 | } 165 | catch(exception) 166 | { 167 | auto exc = context.getException(); 168 | std::cerr << (exc.isError() ? "Error: " : "Throw: ") << (std::string)exc << std::endl; 169 | if((bool)exc["stack"]) 170 | std::cerr << (std::string)exc["stack"] << std::endl; 171 | 172 | js_std_free_handlers(rt); 173 | return 1; 174 | } 175 | 176 | js_std_loop(ctx); 177 | 178 | js_std_free_handlers(rt); 179 | 180 | return 0; 181 | 182 | } 183 | -------------------------------------------------------------------------------- /test/inheritance.cpp: -------------------------------------------------------------------------------- 1 | #include "quickjspp.hpp" 2 | #include 3 | 4 | struct A { 5 | int a; 6 | A(int a) : a(a) {} 7 | virtual ~A() = default; 8 | virtual int vfunc_a1() { 9 | return a; 10 | } 11 | virtual int vfunc_a2() { 12 | return a + 1; 13 | } 14 | int non_vfunc_a1() { 15 | return a + 2; 16 | } 17 | int non_vfunc_a2() { 18 | return a + 3; 19 | } 20 | }; 21 | 22 | struct B { 23 | int b; 24 | B(int b) : b(b) {} 25 | virtual ~B() = default; 26 | virtual int vfunc_b1() { 27 | return b; 28 | } 29 | virtual int vfunc_b2() { 30 | return b + 1; 31 | } 32 | int non_vfunc_b1() { 33 | return b + 2; 34 | } 35 | int non_vfunc_b2() { 36 | return b + 3; 37 | } 38 | }; 39 | 40 | struct H { 41 | int h; 42 | H(int h) : h(h) {} 43 | virtual ~H() = default; 44 | virtual int vfunc_h1() { 45 | return h; 46 | } 47 | virtual int vfunc_h2() { 48 | return h + 1; 49 | } 50 | int non_vfunc_h1() { 51 | return h + 2; 52 | } 53 | int non_vfunc_h2() { 54 | return h + 3; 55 | } 56 | }; 57 | 58 | struct C : public A, public B, public H { 59 | int c; 60 | C(int a, int b, int c, int h) : A(a), B(b), H(h), c(c) {} 61 | int vfunc_a1() override { 62 | return 42; 63 | } 64 | int vfunc_b2() override { 65 | return 84; 66 | } 67 | int non_vfunc_a1() { 68 | return -42; 69 | } 70 | int non_vfunc_b2() { 71 | return -84; 72 | } 73 | int non_vfunc_h1() { 74 | return -126; 75 | } 76 | }; 77 | 78 | 79 | 80 | int main() 81 | { 82 | qjs::Runtime runtime; 83 | qjs::Context context(runtime); 84 | 85 | auto& test = context.addModule("test"); 86 | test.class_("A") 87 | .constructor() 88 | .fun<&A::a>("a") 89 | .fun<&A::vfunc_a1>("vfunc_a1") 90 | .fun<&A::vfunc_a2>("vfunc_a2") 91 | .fun<&A::non_vfunc_a1>("non_vfunc_a1") 92 | .fun<&A::non_vfunc_a2>("non_vfunc_a2"); 93 | 94 | test.class_("B") 95 | .constructor() 96 | .fun<&B::b>("b") 97 | .fun<&B::vfunc_b1>("vfunc_b1") 98 | .fun<&B::vfunc_b2>("vfunc_b2") 99 | .fun<&B::non_vfunc_b1>("non_vfunc_b1") 100 | .fun<&B::non_vfunc_b2>("non_vfunc_b2"); 101 | 102 | test.class_("C") 103 | .constructor() 104 | .base() 105 | .fun<&C::c>("c") 106 | .fun<&C::b>("b") 107 | .fun<&C::h>("h") 108 | .fun<&C::vfunc_b1>("vfunc_b1") 109 | .fun<&C::vfunc_b2>("vfunc_b2") 110 | .fun<&C::vfunc_h1>("vfunc_h1") 111 | .fun<&C::vfunc_h2>("vfunc_h2") 112 | .fun<&C::non_vfunc_a1>("non_vfunc_a1") 113 | .fun<&C::non_vfunc_b1>("non_vfunc_b1") 114 | .fun<&C::non_vfunc_b2>("non_vfunc_b2") 115 | .fun<&C::non_vfunc_h1>("non_vfunc_h1") 116 | .fun<&C::non_vfunc_h2>("non_vfunc_h2"); 117 | 118 | try { 119 | context.eval(R"xxx( 120 | import { A, B, C } from "test"; 121 | 122 | function assert(b, str = "FAIL") { 123 | if (b) { 124 | return; 125 | } else { 126 | throw Error("assertion failed: " + str); 127 | } 128 | } 129 | 130 | function assert_eq(a, b, str = "") { 131 | assert(a === b, `${JSON.stringify(a)} should be equal to ${JSON.stringify(b)}. ${str}`); 132 | } 133 | 134 | function assert_throw(g, str = "") { 135 | try { 136 | f(); 137 | assert(false, `Expression should have thrown`) 138 | } catch (e) { 139 | } 140 | } 141 | 142 | // A 143 | const a = new A(123); 144 | 145 | assert_eq(a.a, 123, "a.a == 123"); 146 | assert_eq(a.vfunc_a1(), 123, "a.vfunc_a1() == 123"); 147 | assert_eq(a.vfunc_a2(), 124, "a.vfunc_a2() == 124"); 148 | assert_eq(a.non_vfunc_a1(), 125, "a.non_vfunc_a1() == 125"); 149 | assert_eq(a.non_vfunc_a2(), 126, "a.non_vfunc_a2() == 126"); 150 | 151 | // B 152 | const b = new B(123); 153 | 154 | assert_eq(b.b, 123, "b.b == 123"); 155 | assert_eq(b.vfunc_b1(), 123, "b.vfunc_b1() == 123"); 156 | assert_eq(b.vfunc_b2(), 124, "b.vfunc_b2() == 124"); 157 | assert_eq(b.non_vfunc_b1(), 125, "b.non_vfunc_b1() == 125"); 158 | assert_eq(b.non_vfunc_b2(), 126, "b.non_vfunc_b2() == 126"); 159 | 160 | // These should throw because A can't be casted to B 161 | assert_throw(() => b.vfunc_b1.call(a), "b.vfunc_b1.call(a)"); 162 | assert_throw(() => b.vfunc_b2.call(a), "b.vfunc_b2.call(a)"); 163 | assert_throw(() => b.non_vfunc_b1.call(a), "b.non_vfunc_b1.call(a)"); 164 | assert_throw(() => b.non_vfunc_b2.call(a), "b.non_vfunc_b2.call(a)"); 165 | 166 | // C 167 | const c = new C(10, 20, 30, 40); 168 | 169 | assert_eq(c.c, 30, "c.c == 30"); 170 | 171 | assert_eq(c instanceof A, true, "(c instanceof A) == true"); 172 | assert_eq(c instanceof B, false, "(c instanceof B) == false"); 173 | 174 | // Properties and methods inherited from A should work on C 175 | // These are the basic test 176 | assert_eq(c.a, 10, "c.a == 10"); 177 | assert_eq(c.vfunc_a1(), 42, "c.vfunc_a1() == 42"); 178 | assert_eq(c.vfunc_a2(), 11, "c.vfunc_a2() == 11"); 179 | assert_eq(c.non_vfunc_a1(), -42, "c.non_vfunc_a1() == -42"); 180 | assert_eq(c.non_vfunc_a2(), 13, "c.non_vfunc_a2() == 13"); 181 | 182 | // Check the behaviour of using A's methods on a C object 183 | // These test the behavior of virtual and non virtual functions 184 | assert_eq(a.vfunc_a1.call(c), 42, "a.vfunc_a1.call(c) == 42"); 185 | assert_eq(a.vfunc_a2.call(c), 11, "a.vfunc_a2.call(c) == 11"); 186 | assert_eq(a.non_vfunc_a1.call(c), 12, "a.non_vfunc_a1.call(c) == 12"); 187 | assert_eq(a.non_vfunc_a2.call(c), 13, "a.non_vfunc_a2.call(c) == 13"); 188 | 189 | // Properties and methods inherited from B should work on C 190 | // The interest of these test cases is that B is not the first inherited class 191 | assert_eq(c.b, 20, "c.b == 20"); 192 | assert_eq(c.vfunc_b1(), 20, "c.vfunc_b1() == 20"); 193 | assert_eq(c.vfunc_b2(), 84, "c.vfunc_b2() == 84"); 194 | assert_eq(c.non_vfunc_b1(), 22, "c.non_vfunc_b1() == 22"); 195 | assert_eq(c.non_vfunc_b2(), -84, "c.non_vfunc_b2() == -84"); 196 | 197 | // Check the behaviour of using B's methods on a C object 198 | // These test the behavior of virtual and non virtual functions 199 | assert_eq(b.vfunc_b1.call(c), 20, "b.vfunc_b1.call(c) == 20"); 200 | assert_eq(b.vfunc_b2.call(c), 84, "b.vfunc_b2.call(c) == 84"); 201 | assert_eq(b.non_vfunc_b1.call(c), 22, "b.non_vfunc_b1.call(c) == 22"); 202 | assert_eq(b.non_vfunc_b2.call(c), 23, "b.non_vfunc_b2.call(c) == 23"); 203 | 204 | // Properties and methods inherited from H should work on C 205 | // The interest of these test cases is that H is never registered with JS 206 | assert_eq(c.h, 40, "c.h == 40"); 207 | assert_eq(c.vfunc_h1(), 40, "c.vfunc_h1() == 40"); 208 | assert_eq(c.vfunc_h2(), 41, "c.vfunc_h2() == 41"); 209 | assert_eq(c.non_vfunc_h1(), -126, "c.non_vfunc_h1() == -126"); 210 | assert_eq(c.non_vfunc_h2(), 43, "c.non_vfunc_h2() == 43"); 211 | 212 | )xxx", "", JS_EVAL_TYPE_MODULE); 213 | } 214 | catch(qjs::exception) 215 | { 216 | auto exc = context.getException(); 217 | std::cerr << (std::string) exc << std::endl; 218 | if((bool) exc["stack"]) 219 | std::cerr << (std::string) exc["stack"] << std::endl; 220 | return 1; 221 | } 222 | 223 | return 0; 224 | } -------------------------------------------------------------------------------- /quickjs/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/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 | -------------------------------------------------------------------------------- /quickjs/quickjs-opcode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS opcode 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 FMT 27 | FMT(none) 28 | FMT(none_int) 29 | FMT(none_loc) 30 | FMT(none_arg) 31 | FMT(none_var_ref) 32 | FMT(u8) 33 | FMT(i8) 34 | FMT(loc8) 35 | FMT(const8) 36 | FMT(label8) 37 | FMT(u16) 38 | FMT(i16) 39 | FMT(label16) 40 | FMT(npop) 41 | FMT(npopx) 42 | FMT(npop_u16) 43 | FMT(loc) 44 | FMT(arg) 45 | FMT(var_ref) 46 | FMT(u32) 47 | FMT(i32) 48 | FMT(const) 49 | FMT(label) 50 | FMT(atom) 51 | FMT(atom_u8) 52 | FMT(atom_u16) 53 | FMT(atom_label_u8) 54 | FMT(atom_label_u16) 55 | FMT(label_u16) 56 | #undef FMT 57 | #endif /* FMT */ 58 | 59 | #ifdef DEF 60 | 61 | #ifndef def 62 | #define def(id, size, n_pop, n_push, f) DEF(id, size, n_pop, n_push, f) 63 | #endif 64 | 65 | DEF(invalid, 1, 0, 0, none) /* never emitted */ 66 | 67 | /* push values */ 68 | DEF( push_i32, 5, 0, 1, i32) 69 | DEF( push_const, 5, 0, 1, const) 70 | DEF( fclosure, 5, 0, 1, const) /* must follow push_const */ 71 | DEF(push_atom_value, 5, 0, 1, atom) 72 | DEF( private_symbol, 5, 0, 1, atom) 73 | DEF( undefined, 1, 0, 1, none) 74 | DEF( null, 1, 0, 1, none) 75 | DEF( push_this, 1, 0, 1, none) /* only used at the start of a function */ 76 | DEF( push_false, 1, 0, 1, none) 77 | DEF( push_true, 1, 0, 1, none) 78 | DEF( object, 1, 0, 1, none) 79 | DEF( special_object, 2, 0, 1, u8) /* only used at the start of a function */ 80 | DEF( rest, 3, 0, 1, u16) /* only used at the start of a function */ 81 | 82 | DEF( drop, 1, 1, 0, none) /* a -> */ 83 | DEF( nip, 1, 2, 1, none) /* a b -> b */ 84 | DEF( nip1, 1, 3, 2, none) /* a b c -> b c */ 85 | DEF( dup, 1, 1, 2, none) /* a -> a a */ 86 | DEF( dup1, 1, 2, 3, none) /* a b -> a a b */ 87 | DEF( dup2, 1, 2, 4, none) /* a b -> a b a b */ 88 | DEF( dup3, 1, 3, 6, none) /* a b c -> a b c a b c */ 89 | DEF( insert2, 1, 2, 3, none) /* obj a -> a obj a (dup_x1) */ 90 | DEF( insert3, 1, 3, 4, none) /* obj prop a -> a obj prop a (dup_x2) */ 91 | DEF( insert4, 1, 4, 5, none) /* this obj prop a -> a this obj prop a */ 92 | DEF( perm3, 1, 3, 3, none) /* obj a b -> a obj b */ 93 | DEF( perm4, 1, 4, 4, none) /* obj prop a b -> a obj prop b */ 94 | DEF( perm5, 1, 5, 5, none) /* this obj prop a b -> a this obj prop b */ 95 | DEF( swap, 1, 2, 2, none) /* a b -> b a */ 96 | DEF( swap2, 1, 4, 4, none) /* a b c d -> c d a b */ 97 | DEF( rot3l, 1, 3, 3, none) /* x a b -> a b x */ 98 | DEF( rot3r, 1, 3, 3, none) /* a b x -> x a b */ 99 | DEF( rot4l, 1, 4, 4, none) /* x a b c -> a b c x */ 100 | DEF( rot5l, 1, 5, 5, none) /* x a b c d -> a b c d x */ 101 | 102 | DEF(call_constructor, 3, 2, 1, npop) /* func new.target args -> ret. arguments are not counted in n_pop */ 103 | DEF( call, 3, 1, 1, npop) /* arguments are not counted in n_pop */ 104 | DEF( tail_call, 3, 1, 0, npop) /* arguments are not counted in n_pop */ 105 | DEF( call_method, 3, 2, 1, npop) /* arguments are not counted in n_pop */ 106 | DEF(tail_call_method, 3, 2, 0, npop) /* arguments are not counted in n_pop */ 107 | DEF( array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */ 108 | DEF( apply, 3, 3, 1, u16) 109 | DEF( return, 1, 1, 0, none) 110 | DEF( return_undef, 1, 0, 0, none) 111 | DEF(check_ctor_return, 1, 1, 2, none) 112 | DEF( check_ctor, 1, 0, 0, none) 113 | DEF( init_ctor, 1, 0, 1, none) 114 | DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */ 115 | DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */ 116 | DEF( return_async, 1, 1, 0, none) 117 | DEF( throw, 1, 1, 0, none) 118 | DEF( throw_error, 6, 0, 0, atom_u8) 119 | DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */ 120 | DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */ 121 | DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a 122 | bytecode string */ 123 | DEF( get_super, 1, 1, 1, none) 124 | DEF( import, 1, 2, 1, none) /* dynamic module import */ 125 | 126 | DEF( check_var, 5, 0, 1, atom) /* check if a variable exists */ 127 | DEF( get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not exist */ 128 | DEF( get_var, 5, 0, 1, atom) /* throw an exception if the variable does not exist */ 129 | DEF( put_var, 5, 1, 0, atom) /* must come after get_var */ 130 | DEF( put_var_init, 5, 1, 0, atom) /* must come after put_var. Used to initialize a global lexical variable */ 131 | DEF( put_var_strict, 5, 2, 0, atom) /* for strict mode variable write */ 132 | 133 | DEF( get_ref_value, 1, 2, 3, none) 134 | DEF( put_ref_value, 1, 3, 0, none) 135 | 136 | DEF( define_var, 6, 0, 0, atom_u8) 137 | DEF(check_define_var, 6, 0, 0, atom_u8) 138 | DEF( define_func, 6, 1, 0, atom_u8) 139 | DEF( get_field, 5, 1, 1, atom) 140 | DEF( get_field2, 5, 1, 2, atom) 141 | DEF( put_field, 5, 2, 0, atom) 142 | DEF( get_private_field, 1, 2, 1, none) /* obj prop -> value */ 143 | DEF( put_private_field, 1, 3, 0, none) /* obj value prop -> */ 144 | DEF(define_private_field, 1, 3, 1, none) /* obj prop value -> obj */ 145 | DEF( get_array_el, 1, 2, 1, none) 146 | DEF( get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */ 147 | DEF( get_array_el3, 1, 2, 3, none) /* obj prop -> obj prop1 value */ 148 | DEF( put_array_el, 1, 3, 0, none) 149 | DEF(get_super_value, 1, 3, 1, none) /* this obj prop -> value */ 150 | DEF(put_super_value, 1, 4, 0, none) /* this obj prop value -> */ 151 | DEF( define_field, 5, 2, 1, atom) 152 | DEF( set_name, 5, 1, 1, atom) 153 | DEF(set_name_computed, 1, 2, 2, none) 154 | DEF( set_proto, 1, 2, 1, none) 155 | DEF(set_home_object, 1, 2, 2, none) 156 | DEF(define_array_el, 1, 3, 2, none) 157 | DEF( append, 1, 3, 2, none) /* append enumerated object, update length */ 158 | DEF(copy_data_properties, 2, 3, 3, u8) 159 | DEF( define_method, 6, 2, 1, atom_u8) 160 | DEF(define_method_computed, 2, 3, 1, u8) /* must come after define_method */ 161 | DEF( define_class, 6, 2, 2, atom_u8) /* parent ctor -> ctor proto */ 162 | DEF( define_class_computed, 6, 3, 3, atom_u8) /* field_name parent ctor -> field_name ctor proto (class with computed name) */ 163 | 164 | DEF( get_loc, 3, 0, 1, loc) 165 | DEF( put_loc, 3, 1, 0, loc) /* must come after get_loc */ 166 | DEF( set_loc, 3, 1, 1, loc) /* must come after put_loc */ 167 | DEF( get_arg, 3, 0, 1, arg) 168 | DEF( put_arg, 3, 1, 0, arg) /* must come after get_arg */ 169 | DEF( set_arg, 3, 1, 1, arg) /* must come after put_arg */ 170 | DEF( get_var_ref, 3, 0, 1, var_ref) 171 | DEF( put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */ 172 | DEF( set_var_ref, 3, 1, 1, var_ref) /* must come after put_var_ref */ 173 | DEF(set_loc_uninitialized, 3, 0, 0, loc) 174 | DEF( get_loc_check, 3, 0, 1, loc) 175 | DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */ 176 | DEF( put_loc_check_init, 3, 1, 0, loc) 177 | DEF(get_loc_checkthis, 3, 0, 1, loc) 178 | DEF(get_var_ref_check, 3, 0, 1, var_ref) 179 | DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */ 180 | DEF(put_var_ref_check_init, 3, 1, 0, var_ref) 181 | DEF( close_loc, 3, 0, 0, loc) 182 | DEF( if_false, 5, 1, 0, label) 183 | DEF( if_true, 5, 1, 0, label) /* must come after if_false */ 184 | DEF( goto, 5, 0, 0, label) /* must come after if_true */ 185 | DEF( catch, 5, 0, 1, label) 186 | DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */ 187 | DEF( ret, 1, 1, 0, none) /* used to return from the finally block */ 188 | DEF( nip_catch, 1, 2, 1, none) /* catch ... a -> a */ 189 | 190 | DEF( to_object, 1, 1, 1, none) 191 | //DEF( to_string, 1, 1, 1, none) 192 | DEF( to_propkey, 1, 1, 1, none) 193 | 194 | DEF( with_get_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ 195 | DEF( with_put_var, 10, 2, 1, atom_label_u8) /* must be in the same order as scope_xxx */ 196 | DEF(with_delete_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ 197 | DEF( with_make_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ 198 | DEF( with_get_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ 199 | 200 | DEF( make_loc_ref, 7, 0, 2, atom_u16) 201 | DEF( make_arg_ref, 7, 0, 2, atom_u16) 202 | DEF(make_var_ref_ref, 7, 0, 2, atom_u16) 203 | DEF( make_var_ref, 5, 0, 2, atom) 204 | 205 | DEF( for_in_start, 1, 1, 1, none) 206 | DEF( for_of_start, 1, 1, 3, none) 207 | DEF(for_await_of_start, 1, 1, 3, none) 208 | DEF( for_in_next, 1, 1, 3, none) 209 | DEF( for_of_next, 2, 3, 5, u8) 210 | DEF(for_await_of_next, 1, 3, 4, none) /* iter next catch_offset -> iter next catch_offset obj */ 211 | DEF(iterator_check_object, 1, 1, 1, none) 212 | DEF(iterator_get_value_done, 1, 2, 3, none) /* catch_offset obj -> catch_offset value done */ 213 | DEF( iterator_close, 1, 3, 0, none) 214 | DEF( iterator_next, 1, 4, 4, none) 215 | DEF( iterator_call, 2, 4, 5, u8) 216 | DEF( initial_yield, 1, 0, 0, none) 217 | DEF( yield, 1, 1, 2, none) 218 | DEF( yield_star, 1, 1, 2, none) 219 | DEF(async_yield_star, 1, 1, 2, none) 220 | DEF( await, 1, 1, 1, none) 221 | 222 | /* arithmetic/logic operations */ 223 | DEF( neg, 1, 1, 1, none) 224 | DEF( plus, 1, 1, 1, none) 225 | DEF( dec, 1, 1, 1, none) 226 | DEF( inc, 1, 1, 1, none) 227 | DEF( post_dec, 1, 1, 2, none) 228 | DEF( post_inc, 1, 1, 2, none) 229 | DEF( dec_loc, 2, 0, 0, loc8) 230 | DEF( inc_loc, 2, 0, 0, loc8) 231 | DEF( add_loc, 2, 1, 0, loc8) 232 | DEF( not, 1, 1, 1, none) 233 | DEF( lnot, 1, 1, 1, none) 234 | DEF( typeof, 1, 1, 1, none) 235 | DEF( delete, 1, 2, 1, none) 236 | DEF( delete_var, 5, 0, 1, atom) 237 | 238 | DEF( mul, 1, 2, 1, none) 239 | DEF( div, 1, 2, 1, none) 240 | DEF( mod, 1, 2, 1, none) 241 | DEF( add, 1, 2, 1, none) 242 | DEF( sub, 1, 2, 1, none) 243 | DEF( pow, 1, 2, 1, none) 244 | DEF( shl, 1, 2, 1, none) 245 | DEF( sar, 1, 2, 1, none) 246 | DEF( shr, 1, 2, 1, none) 247 | DEF( lt, 1, 2, 1, none) 248 | DEF( lte, 1, 2, 1, none) 249 | DEF( gt, 1, 2, 1, none) 250 | DEF( gte, 1, 2, 1, none) 251 | DEF( instanceof, 1, 2, 1, none) 252 | DEF( in, 1, 2, 1, none) 253 | DEF( eq, 1, 2, 1, none) 254 | DEF( neq, 1, 2, 1, none) 255 | DEF( strict_eq, 1, 2, 1, none) 256 | DEF( strict_neq, 1, 2, 1, none) 257 | DEF( and, 1, 2, 1, none) 258 | DEF( xor, 1, 2, 1, none) 259 | DEF( or, 1, 2, 1, none) 260 | DEF(is_undefined_or_null, 1, 1, 1, none) 261 | DEF( private_in, 1, 2, 1, none) 262 | DEF(push_bigint_i32, 5, 0, 1, i32) 263 | /* must be the last non short and non temporary opcode */ 264 | DEF( nop, 1, 0, 0, none) 265 | 266 | /* temporary opcodes: never emitted in the final bytecode */ 267 | 268 | def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ 269 | def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ 270 | 271 | def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */ 272 | 273 | /* the following opcodes must be in the same order as the 'with_x' and 274 | get_var_undef, get_var and put_var opcodes */ 275 | def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ 276 | def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ 277 | def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */ 278 | def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ 279 | def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */ 280 | def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ 281 | def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ 282 | def(scope_get_var_checkthis, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2, only used to return 'this' in derived class constructors */ 283 | def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */ 284 | def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */ 285 | def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */ 286 | def(scope_in_private_field, 7, 1, 1, atom_u16) /* obj -> res emitted in phase 1, removed in phase 2 */ 287 | def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */ 288 | def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */ 289 | def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */ 290 | 291 | def( line_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */ 292 | 293 | #if SHORT_OPCODES 294 | DEF( push_minus1, 1, 0, 1, none_int) 295 | DEF( push_0, 1, 0, 1, none_int) 296 | DEF( push_1, 1, 0, 1, none_int) 297 | DEF( push_2, 1, 0, 1, none_int) 298 | DEF( push_3, 1, 0, 1, none_int) 299 | DEF( push_4, 1, 0, 1, none_int) 300 | DEF( push_5, 1, 0, 1, none_int) 301 | DEF( push_6, 1, 0, 1, none_int) 302 | DEF( push_7, 1, 0, 1, none_int) 303 | DEF( push_i8, 2, 0, 1, i8) 304 | DEF( push_i16, 3, 0, 1, i16) 305 | DEF( push_const8, 2, 0, 1, const8) 306 | DEF( fclosure8, 2, 0, 1, const8) /* must follow push_const8 */ 307 | DEF(push_empty_string, 1, 0, 1, none) 308 | 309 | DEF( get_loc8, 2, 0, 1, loc8) 310 | DEF( put_loc8, 2, 1, 0, loc8) 311 | DEF( set_loc8, 2, 1, 1, loc8) 312 | 313 | DEF( get_loc0, 1, 0, 1, none_loc) 314 | DEF( get_loc1, 1, 0, 1, none_loc) 315 | DEF( get_loc2, 1, 0, 1, none_loc) 316 | DEF( get_loc3, 1, 0, 1, none_loc) 317 | DEF( put_loc0, 1, 1, 0, none_loc) 318 | DEF( put_loc1, 1, 1, 0, none_loc) 319 | DEF( put_loc2, 1, 1, 0, none_loc) 320 | DEF( put_loc3, 1, 1, 0, none_loc) 321 | DEF( set_loc0, 1, 1, 1, none_loc) 322 | DEF( set_loc1, 1, 1, 1, none_loc) 323 | DEF( set_loc2, 1, 1, 1, none_loc) 324 | DEF( set_loc3, 1, 1, 1, none_loc) 325 | DEF( get_arg0, 1, 0, 1, none_arg) 326 | DEF( get_arg1, 1, 0, 1, none_arg) 327 | DEF( get_arg2, 1, 0, 1, none_arg) 328 | DEF( get_arg3, 1, 0, 1, none_arg) 329 | DEF( put_arg0, 1, 1, 0, none_arg) 330 | DEF( put_arg1, 1, 1, 0, none_arg) 331 | DEF( put_arg2, 1, 1, 0, none_arg) 332 | DEF( put_arg3, 1, 1, 0, none_arg) 333 | DEF( set_arg0, 1, 1, 1, none_arg) 334 | DEF( set_arg1, 1, 1, 1, none_arg) 335 | DEF( set_arg2, 1, 1, 1, none_arg) 336 | DEF( set_arg3, 1, 1, 1, none_arg) 337 | DEF( get_var_ref0, 1, 0, 1, none_var_ref) 338 | DEF( get_var_ref1, 1, 0, 1, none_var_ref) 339 | DEF( get_var_ref2, 1, 0, 1, none_var_ref) 340 | DEF( get_var_ref3, 1, 0, 1, none_var_ref) 341 | DEF( put_var_ref0, 1, 1, 0, none_var_ref) 342 | DEF( put_var_ref1, 1, 1, 0, none_var_ref) 343 | DEF( put_var_ref2, 1, 1, 0, none_var_ref) 344 | DEF( put_var_ref3, 1, 1, 0, none_var_ref) 345 | DEF( set_var_ref0, 1, 1, 1, none_var_ref) 346 | DEF( set_var_ref1, 1, 1, 1, none_var_ref) 347 | DEF( set_var_ref2, 1, 1, 1, none_var_ref) 348 | DEF( set_var_ref3, 1, 1, 1, none_var_ref) 349 | 350 | DEF( get_length, 1, 1, 1, none) 351 | 352 | DEF( if_false8, 2, 1, 0, label8) 353 | DEF( if_true8, 2, 1, 0, label8) /* must come after if_false8 */ 354 | DEF( goto8, 2, 0, 0, label8) /* must come after if_true8 */ 355 | DEF( goto16, 3, 0, 0, label16) 356 | 357 | DEF( call0, 1, 1, 1, npopx) 358 | DEF( call1, 1, 1, 1, npopx) 359 | DEF( call2, 1, 1, 1, npopx) 360 | DEF( call3, 1, 1, 1, npopx) 361 | 362 | DEF( is_undefined, 1, 1, 1, none) 363 | DEF( is_null, 1, 1, 1, none) 364 | DEF(typeof_is_undefined, 1, 1, 1, none) 365 | DEF( typeof_is_function, 1, 1, 1, none) 366 | #endif 367 | 368 | #undef DEF 369 | #undef def 370 | #endif /* DEF */ 371 | -------------------------------------------------------------------------------- /quickjs/cutils.c: -------------------------------------------------------------------------------- 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 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "cutils.h" 31 | 32 | void pstrcpy(char *buf, int buf_size, const char *str) 33 | { 34 | int c; 35 | char *q = buf; 36 | 37 | if (buf_size <= 0) 38 | return; 39 | 40 | for(;;) { 41 | c = *str++; 42 | if (c == 0 || q >= buf + buf_size - 1) 43 | break; 44 | *q++ = c; 45 | } 46 | *q = '\0'; 47 | } 48 | 49 | /* strcat and truncate. */ 50 | char *pstrcat(char *buf, int buf_size, const char *s) 51 | { 52 | int len; 53 | len = strlen(buf); 54 | if (len < buf_size) 55 | pstrcpy(buf + len, buf_size - len, s); 56 | return buf; 57 | } 58 | 59 | int strstart(const char *str, const char *val, const char **ptr) 60 | { 61 | const char *p, *q; 62 | p = str; 63 | q = val; 64 | while (*q != '\0') { 65 | if (*p != *q) 66 | return 0; 67 | p++; 68 | q++; 69 | } 70 | if (ptr) 71 | *ptr = p; 72 | return 1; 73 | } 74 | 75 | int has_suffix(const char *str, const char *suffix) 76 | { 77 | size_t len = strlen(str); 78 | size_t slen = strlen(suffix); 79 | return (len >= slen && !memcmp(str + len - slen, suffix, slen)); 80 | } 81 | 82 | /* Dynamic buffer package */ 83 | 84 | static void *dbuf_default_realloc(void *opaque, void *ptr, size_t size) 85 | { 86 | return realloc(ptr, size); 87 | } 88 | 89 | void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func) 90 | { 91 | memset(s, 0, sizeof(*s)); 92 | if (!realloc_func) 93 | realloc_func = dbuf_default_realloc; 94 | s->opaque = opaque; 95 | s->realloc_func = realloc_func; 96 | } 97 | 98 | void dbuf_init(DynBuf *s) 99 | { 100 | dbuf_init2(s, NULL, NULL); 101 | } 102 | 103 | /* return < 0 if error */ 104 | int dbuf_realloc(DynBuf *s, size_t new_size) 105 | { 106 | size_t size; 107 | uint8_t *new_buf; 108 | if (new_size > s->allocated_size) { 109 | if (s->error) 110 | return -1; 111 | size = s->allocated_size * 3 / 2; 112 | if (size > new_size) 113 | new_size = size; 114 | new_buf = s->realloc_func(s->opaque, s->buf, new_size); 115 | if (!new_buf) { 116 | s->error = TRUE; 117 | return -1; 118 | } 119 | s->buf = new_buf; 120 | s->allocated_size = new_size; 121 | } 122 | return 0; 123 | } 124 | 125 | int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len) 126 | { 127 | size_t end; 128 | end = offset + len; 129 | if (dbuf_realloc(s, end)) 130 | return -1; 131 | memcpy(s->buf + offset, data, len); 132 | if (end > s->size) 133 | s->size = end; 134 | return 0; 135 | } 136 | 137 | int dbuf_put(DynBuf *s, const uint8_t *data, size_t len) 138 | { 139 | if (unlikely((s->size + len) > s->allocated_size)) { 140 | if (dbuf_realloc(s, s->size + len)) 141 | return -1; 142 | } 143 | memcpy_no_ub(s->buf + s->size, data, len); 144 | s->size += len; 145 | return 0; 146 | } 147 | 148 | int dbuf_put_self(DynBuf *s, size_t offset, size_t len) 149 | { 150 | if (unlikely((s->size + len) > s->allocated_size)) { 151 | if (dbuf_realloc(s, s->size + len)) 152 | return -1; 153 | } 154 | memcpy(s->buf + s->size, s->buf + offset, len); 155 | s->size += len; 156 | return 0; 157 | } 158 | 159 | int dbuf_putc(DynBuf *s, uint8_t c) 160 | { 161 | return dbuf_put(s, &c, 1); 162 | } 163 | 164 | int dbuf_putstr(DynBuf *s, const char *str) 165 | { 166 | return dbuf_put(s, (const uint8_t *)str, strlen(str)); 167 | } 168 | 169 | int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s, 170 | const char *fmt, ...) 171 | { 172 | va_list ap; 173 | char buf[128]; 174 | int len; 175 | 176 | va_start(ap, fmt); 177 | len = vsnprintf(buf, sizeof(buf), fmt, ap); 178 | va_end(ap); 179 | if (len < 0) 180 | return -1; 181 | if (len < sizeof(buf)) { 182 | /* fast case */ 183 | return dbuf_put(s, (uint8_t *)buf, len); 184 | } else { 185 | if (dbuf_realloc(s, s->size + len + 1)) 186 | return -1; 187 | va_start(ap, fmt); 188 | vsnprintf((char *)(s->buf + s->size), s->allocated_size - s->size, 189 | fmt, ap); 190 | va_end(ap); 191 | s->size += len; 192 | } 193 | return 0; 194 | } 195 | 196 | void dbuf_free(DynBuf *s) 197 | { 198 | /* we test s->buf as a fail safe to avoid crashing if dbuf_free() 199 | is called twice */ 200 | if (s->buf) { 201 | s->realloc_func(s->opaque, s->buf, 0); 202 | } 203 | memset(s, 0, sizeof(*s)); 204 | } 205 | 206 | /* Note: at most 31 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes 207 | are output. */ 208 | int unicode_to_utf8(uint8_t *buf, unsigned int c) 209 | { 210 | uint8_t *q = buf; 211 | 212 | if (c < 0x80) { 213 | *q++ = c; 214 | } else { 215 | if (c < 0x800) { 216 | *q++ = (c >> 6) | 0xc0; 217 | } else { 218 | if (c < 0x10000) { 219 | *q++ = (c >> 12) | 0xe0; 220 | } else { 221 | if (c < 0x00200000) { 222 | *q++ = (c >> 18) | 0xf0; 223 | } else { 224 | if (c < 0x04000000) { 225 | *q++ = (c >> 24) | 0xf8; 226 | } else if (c < 0x80000000) { 227 | *q++ = (c >> 30) | 0xfc; 228 | *q++ = ((c >> 24) & 0x3f) | 0x80; 229 | } else { 230 | return 0; 231 | } 232 | *q++ = ((c >> 18) & 0x3f) | 0x80; 233 | } 234 | *q++ = ((c >> 12) & 0x3f) | 0x80; 235 | } 236 | *q++ = ((c >> 6) & 0x3f) | 0x80; 237 | } 238 | *q++ = (c & 0x3f) | 0x80; 239 | } 240 | return q - buf; 241 | } 242 | 243 | static const unsigned int utf8_min_code[5] = { 244 | 0x80, 0x800, 0x10000, 0x00200000, 0x04000000, 245 | }; 246 | 247 | static const unsigned char utf8_first_code_mask[5] = { 248 | 0x1f, 0xf, 0x7, 0x3, 0x1, 249 | }; 250 | 251 | /* return -1 if error. *pp is not updated in this case. max_len must 252 | be >= 1. The maximum length for a UTF8 byte sequence is 6 bytes. */ 253 | int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp) 254 | { 255 | int l, c, b, i; 256 | 257 | c = *p++; 258 | if (c < 0x80) { 259 | *pp = p; 260 | return c; 261 | } 262 | switch(c) { 263 | case 0xc0: case 0xc1: case 0xc2: case 0xc3: 264 | case 0xc4: case 0xc5: case 0xc6: case 0xc7: 265 | case 0xc8: case 0xc9: case 0xca: case 0xcb: 266 | case 0xcc: case 0xcd: case 0xce: case 0xcf: 267 | case 0xd0: case 0xd1: case 0xd2: case 0xd3: 268 | case 0xd4: case 0xd5: case 0xd6: case 0xd7: 269 | case 0xd8: case 0xd9: case 0xda: case 0xdb: 270 | case 0xdc: case 0xdd: case 0xde: case 0xdf: 271 | l = 1; 272 | break; 273 | case 0xe0: case 0xe1: case 0xe2: case 0xe3: 274 | case 0xe4: case 0xe5: case 0xe6: case 0xe7: 275 | case 0xe8: case 0xe9: case 0xea: case 0xeb: 276 | case 0xec: case 0xed: case 0xee: case 0xef: 277 | l = 2; 278 | break; 279 | case 0xf0: case 0xf1: case 0xf2: case 0xf3: 280 | case 0xf4: case 0xf5: case 0xf6: case 0xf7: 281 | l = 3; 282 | break; 283 | case 0xf8: case 0xf9: case 0xfa: case 0xfb: 284 | l = 4; 285 | break; 286 | case 0xfc: case 0xfd: 287 | l = 5; 288 | break; 289 | default: 290 | return -1; 291 | } 292 | /* check that we have enough characters */ 293 | if (l > (max_len - 1)) 294 | return -1; 295 | c &= utf8_first_code_mask[l - 1]; 296 | for(i = 0; i < l; i++) { 297 | b = *p++; 298 | if (b < 0x80 || b >= 0xc0) 299 | return -1; 300 | c = (c << 6) | (b & 0x3f); 301 | } 302 | if (c < utf8_min_code[l - 1]) 303 | return -1; 304 | *pp = p; 305 | return c; 306 | } 307 | 308 | #if 0 309 | 310 | #if defined(EMSCRIPTEN) || defined(__ANDROID__) 311 | 312 | static void *rqsort_arg; 313 | static int (*rqsort_cmp)(const void *, const void *, void *); 314 | 315 | static int rqsort_cmp2(const void *p1, const void *p2) 316 | { 317 | return rqsort_cmp(p1, p2, rqsort_arg); 318 | } 319 | 320 | /* not reentrant, but not needed with emscripten */ 321 | void rqsort(void *base, size_t nmemb, size_t size, 322 | int (*cmp)(const void *, const void *, void *), 323 | void *arg) 324 | { 325 | rqsort_arg = arg; 326 | rqsort_cmp = cmp; 327 | qsort(base, nmemb, size, rqsort_cmp2); 328 | } 329 | 330 | #endif 331 | 332 | #else 333 | 334 | typedef void (*exchange_f)(void *a, void *b, size_t size); 335 | typedef int (*cmp_f)(const void *, const void *, void *opaque); 336 | 337 | static void exchange_bytes(void *a, void *b, size_t size) { 338 | uint8_t *ap = (uint8_t *)a; 339 | uint8_t *bp = (uint8_t *)b; 340 | 341 | while (size-- != 0) { 342 | uint8_t t = *ap; 343 | *ap++ = *bp; 344 | *bp++ = t; 345 | } 346 | } 347 | 348 | static void exchange_one_byte(void *a, void *b, size_t size) { 349 | uint8_t *ap = (uint8_t *)a; 350 | uint8_t *bp = (uint8_t *)b; 351 | uint8_t t = *ap; 352 | *ap = *bp; 353 | *bp = t; 354 | } 355 | 356 | static void exchange_int16s(void *a, void *b, size_t size) { 357 | uint16_t *ap = (uint16_t *)a; 358 | uint16_t *bp = (uint16_t *)b; 359 | 360 | for (size /= sizeof(uint16_t); size-- != 0;) { 361 | uint16_t t = *ap; 362 | *ap++ = *bp; 363 | *bp++ = t; 364 | } 365 | } 366 | 367 | static void exchange_one_int16(void *a, void *b, size_t size) { 368 | uint16_t *ap = (uint16_t *)a; 369 | uint16_t *bp = (uint16_t *)b; 370 | uint16_t t = *ap; 371 | *ap = *bp; 372 | *bp = t; 373 | } 374 | 375 | static void exchange_int32s(void *a, void *b, size_t size) { 376 | uint32_t *ap = (uint32_t *)a; 377 | uint32_t *bp = (uint32_t *)b; 378 | 379 | for (size /= sizeof(uint32_t); size-- != 0;) { 380 | uint32_t t = *ap; 381 | *ap++ = *bp; 382 | *bp++ = t; 383 | } 384 | } 385 | 386 | static void exchange_one_int32(void *a, void *b, size_t size) { 387 | uint32_t *ap = (uint32_t *)a; 388 | uint32_t *bp = (uint32_t *)b; 389 | uint32_t t = *ap; 390 | *ap = *bp; 391 | *bp = t; 392 | } 393 | 394 | static void exchange_int64s(void *a, void *b, size_t size) { 395 | uint64_t *ap = (uint64_t *)a; 396 | uint64_t *bp = (uint64_t *)b; 397 | 398 | for (size /= sizeof(uint64_t); size-- != 0;) { 399 | uint64_t t = *ap; 400 | *ap++ = *bp; 401 | *bp++ = t; 402 | } 403 | } 404 | 405 | static void exchange_one_int64(void *a, void *b, size_t size) { 406 | uint64_t *ap = (uint64_t *)a; 407 | uint64_t *bp = (uint64_t *)b; 408 | uint64_t t = *ap; 409 | *ap = *bp; 410 | *bp = t; 411 | } 412 | 413 | static void exchange_int128s(void *a, void *b, size_t size) { 414 | uint64_t *ap = (uint64_t *)a; 415 | uint64_t *bp = (uint64_t *)b; 416 | 417 | for (size /= sizeof(uint64_t) * 2; size-- != 0; ap += 2, bp += 2) { 418 | uint64_t t = ap[0]; 419 | uint64_t u = ap[1]; 420 | ap[0] = bp[0]; 421 | ap[1] = bp[1]; 422 | bp[0] = t; 423 | bp[1] = u; 424 | } 425 | } 426 | 427 | static void exchange_one_int128(void *a, void *b, size_t size) { 428 | uint64_t *ap = (uint64_t *)a; 429 | uint64_t *bp = (uint64_t *)b; 430 | uint64_t t = ap[0]; 431 | uint64_t u = ap[1]; 432 | ap[0] = bp[0]; 433 | ap[1] = bp[1]; 434 | bp[0] = t; 435 | bp[1] = u; 436 | } 437 | 438 | static inline exchange_f exchange_func(const void *base, size_t size) { 439 | switch (((uintptr_t)base | (uintptr_t)size) & 15) { 440 | case 0: 441 | if (size == sizeof(uint64_t) * 2) 442 | return exchange_one_int128; 443 | else 444 | return exchange_int128s; 445 | case 8: 446 | if (size == sizeof(uint64_t)) 447 | return exchange_one_int64; 448 | else 449 | return exchange_int64s; 450 | case 4: 451 | case 12: 452 | if (size == sizeof(uint32_t)) 453 | return exchange_one_int32; 454 | else 455 | return exchange_int32s; 456 | case 2: 457 | case 6: 458 | case 10: 459 | case 14: 460 | if (size == sizeof(uint16_t)) 461 | return exchange_one_int16; 462 | else 463 | return exchange_int16s; 464 | default: 465 | if (size == 1) 466 | return exchange_one_byte; 467 | else 468 | return exchange_bytes; 469 | } 470 | } 471 | 472 | static void heapsortx(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque) 473 | { 474 | uint8_t *basep = (uint8_t *)base; 475 | size_t i, n, c, r; 476 | exchange_f swap = exchange_func(base, size); 477 | 478 | if (nmemb > 1) { 479 | i = (nmemb / 2) * size; 480 | n = nmemb * size; 481 | 482 | while (i > 0) { 483 | i -= size; 484 | for (r = i; (c = r * 2 + size) < n; r = c) { 485 | if (c < n - size && cmp(basep + c, basep + c + size, opaque) <= 0) 486 | c += size; 487 | if (cmp(basep + r, basep + c, opaque) > 0) 488 | break; 489 | swap(basep + r, basep + c, size); 490 | } 491 | } 492 | for (i = n - size; i > 0; i -= size) { 493 | swap(basep, basep + i, size); 494 | 495 | for (r = 0; (c = r * 2 + size) < i; r = c) { 496 | if (c < i - size && cmp(basep + c, basep + c + size, opaque) <= 0) 497 | c += size; 498 | if (cmp(basep + r, basep + c, opaque) > 0) 499 | break; 500 | swap(basep + r, basep + c, size); 501 | } 502 | } 503 | } 504 | } 505 | 506 | static inline void *med3(void *a, void *b, void *c, cmp_f cmp, void *opaque) 507 | { 508 | return cmp(a, b, opaque) < 0 ? 509 | (cmp(b, c, opaque) < 0 ? b : (cmp(a, c, opaque) < 0 ? c : a )) : 510 | (cmp(b, c, opaque) > 0 ? b : (cmp(a, c, opaque) < 0 ? a : c )); 511 | } 512 | 513 | /* pointer based version with local stack and insertion sort threshhold */ 514 | void rqsort(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque) 515 | { 516 | struct { uint8_t *base; size_t count; int depth; } stack[50], *sp = stack; 517 | uint8_t *ptr, *pi, *pj, *plt, *pgt, *top, *m; 518 | size_t m4, i, lt, gt, span, span2; 519 | int c, depth; 520 | exchange_f swap = exchange_func(base, size); 521 | exchange_f swap_block = exchange_func(base, size | 128); 522 | 523 | if (nmemb < 2 || size <= 0) 524 | return; 525 | 526 | sp->base = (uint8_t *)base; 527 | sp->count = nmemb; 528 | sp->depth = 0; 529 | sp++; 530 | 531 | while (sp > stack) { 532 | sp--; 533 | ptr = sp->base; 534 | nmemb = sp->count; 535 | depth = sp->depth; 536 | 537 | while (nmemb > 6) { 538 | if (++depth > 50) { 539 | /* depth check to ensure worst case logarithmic time */ 540 | heapsortx(ptr, nmemb, size, cmp, opaque); 541 | nmemb = 0; 542 | break; 543 | } 544 | /* select median of 3 from 1/4, 1/2, 3/4 positions */ 545 | /* should use median of 5 or 9? */ 546 | m4 = (nmemb >> 2) * size; 547 | m = med3(ptr + m4, ptr + 2 * m4, ptr + 3 * m4, cmp, opaque); 548 | swap(ptr, m, size); /* move the pivot to the start or the array */ 549 | i = lt = 1; 550 | pi = plt = ptr + size; 551 | gt = nmemb; 552 | pj = pgt = top = ptr + nmemb * size; 553 | for (;;) { 554 | while (pi < pj && (c = cmp(ptr, pi, opaque)) >= 0) { 555 | if (c == 0) { 556 | swap(plt, pi, size); 557 | lt++; 558 | plt += size; 559 | } 560 | i++; 561 | pi += size; 562 | } 563 | while (pi < (pj -= size) && (c = cmp(ptr, pj, opaque)) <= 0) { 564 | if (c == 0) { 565 | gt--; 566 | pgt -= size; 567 | swap(pgt, pj, size); 568 | } 569 | } 570 | if (pi >= pj) 571 | break; 572 | swap(pi, pj, size); 573 | i++; 574 | pi += size; 575 | } 576 | /* array has 4 parts: 577 | * from 0 to lt excluded: elements identical to pivot 578 | * from lt to pi excluded: elements smaller than pivot 579 | * from pi to gt excluded: elements greater than pivot 580 | * from gt to n excluded: elements identical to pivot 581 | */ 582 | /* move elements identical to pivot in the middle of the array: */ 583 | /* swap values in ranges [0..lt[ and [i-lt..i[ 584 | swapping the smallest span between lt and i-lt is sufficient 585 | */ 586 | span = plt - ptr; 587 | span2 = pi - plt; 588 | lt = i - lt; 589 | if (span > span2) 590 | span = span2; 591 | swap_block(ptr, pi - span, span); 592 | /* swap values in ranges [gt..top[ and [i..top-(top-gt)[ 593 | swapping the smallest span between top-gt and gt-i is sufficient 594 | */ 595 | span = top - pgt; 596 | span2 = pgt - pi; 597 | pgt = top - span2; 598 | gt = nmemb - (gt - i); 599 | if (span > span2) 600 | span = span2; 601 | swap_block(pi, top - span, span); 602 | 603 | /* now array has 3 parts: 604 | * from 0 to lt excluded: elements smaller than pivot 605 | * from lt to gt excluded: elements identical to pivot 606 | * from gt to n excluded: elements greater than pivot 607 | */ 608 | /* stack the larger segment and keep processing the smaller one 609 | to minimize stack use for pathological distributions */ 610 | if (lt > nmemb - gt) { 611 | sp->base = ptr; 612 | sp->count = lt; 613 | sp->depth = depth; 614 | sp++; 615 | ptr = pgt; 616 | nmemb -= gt; 617 | } else { 618 | sp->base = pgt; 619 | sp->count = nmemb - gt; 620 | sp->depth = depth; 621 | sp++; 622 | nmemb = lt; 623 | } 624 | } 625 | /* Use insertion sort for small fragments */ 626 | for (pi = ptr + size, top = ptr + nmemb * size; pi < top; pi += size) { 627 | for (pj = pi; pj > ptr && cmp(pj - size, pj, opaque) > 0; pj -= size) 628 | swap(pj, pj - size, size); 629 | } 630 | } 631 | } 632 | 633 | #endif 634 | -------------------------------------------------------------------------------- /quickjs/quickjs.h: -------------------------------------------------------------------------------- 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 | #ifndef QUICKJS_H 26 | #define QUICKJS_H 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | #if defined(__GNUC__) || defined(__clang__) 37 | #define js_likely(x) __builtin_expect(!!(x), 1) 38 | #define js_unlikely(x) __builtin_expect(!!(x), 0) 39 | #define js_force_inline inline __attribute__((always_inline)) 40 | #define __js_printf_like(f, a) __attribute__((format(printf, f, a))) 41 | #else 42 | #define js_likely(x) (x) 43 | #define js_unlikely(x) (x) 44 | #define js_force_inline inline 45 | #define __js_printf_like(a, b) 46 | #endif 47 | 48 | #define JS_BOOL int 49 | 50 | typedef struct JSRuntime JSRuntime; 51 | typedef struct JSContext JSContext; 52 | typedef struct JSClass JSClass; 53 | typedef uint32_t JSClassID; 54 | typedef uint32_t JSAtom; 55 | 56 | #if INTPTR_MAX >= INT64_MAX 57 | #define JS_PTR64 58 | #define JS_PTR64_DEF(a) a 59 | #else 60 | #define JS_PTR64_DEF(a) 61 | #endif 62 | 63 | #ifndef JS_PTR64 64 | #define JS_NAN_BOXING 65 | #endif 66 | 67 | #if defined(__SIZEOF_INT128__) && (INTPTR_MAX >= INT64_MAX) 68 | #define JS_LIMB_BITS 64 69 | #else 70 | #define JS_LIMB_BITS 32 71 | #endif 72 | 73 | #define JS_SHORT_BIG_INT_BITS JS_LIMB_BITS 74 | 75 | enum { 76 | /* all tags with a reference count are negative */ 77 | JS_TAG_FIRST = -9, /* first negative tag */ 78 | JS_TAG_BIG_INT = -9, 79 | JS_TAG_SYMBOL = -8, 80 | JS_TAG_STRING = -7, 81 | JS_TAG_STRING_ROPE = -6, 82 | JS_TAG_MODULE = -3, /* used internally */ 83 | JS_TAG_FUNCTION_BYTECODE = -2, /* used internally */ 84 | JS_TAG_OBJECT = -1, 85 | 86 | JS_TAG_INT = 0, 87 | JS_TAG_BOOL = 1, 88 | JS_TAG_NULL = 2, 89 | JS_TAG_UNDEFINED = 3, 90 | JS_TAG_UNINITIALIZED = 4, 91 | JS_TAG_CATCH_OFFSET = 5, 92 | JS_TAG_EXCEPTION = 6, 93 | JS_TAG_SHORT_BIG_INT = 7, 94 | JS_TAG_FLOAT64 = 8, 95 | /* any larger tag is FLOAT64 if JS_NAN_BOXING */ 96 | }; 97 | 98 | typedef struct JSRefCountHeader { 99 | int ref_count; 100 | } JSRefCountHeader; 101 | 102 | #define JS_FLOAT64_NAN NAN 103 | 104 | #ifdef CONFIG_CHECK_JSVALUE 105 | /* JSValue consistency : it is not possible to run the code in this 106 | mode, but it is useful to detect simple reference counting 107 | errors. It would be interesting to modify a static C analyzer to 108 | handle specific annotations (clang has such annotations but only 109 | for objective C) */ 110 | typedef struct __JSValue *JSValue; 111 | typedef const struct __JSValue *JSValueConst; 112 | 113 | #define JS_VALUE_GET_TAG(v) (int)((uintptr_t)(v) & 0xf) 114 | /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ 115 | #define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v) 116 | #define JS_VALUE_GET_INT(v) (int)((intptr_t)(v) >> 4) 117 | #define JS_VALUE_GET_BOOL(v) JS_VALUE_GET_INT(v) 118 | #define JS_VALUE_GET_FLOAT64(v) (double)JS_VALUE_GET_INT(v) 119 | #define JS_VALUE_GET_SHORT_BIG_INT(v) JS_VALUE_GET_INT(v) 120 | #define JS_VALUE_GET_PTR(v) (void *)((intptr_t)(v) & ~0xf) 121 | 122 | #define JS_MKVAL(tag, val) (JSValue)(intptr_t)(((val) << 4) | (tag)) 123 | #define JS_MKPTR(tag, p) (JSValue)((intptr_t)(p) | (tag)) 124 | 125 | #define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64) 126 | 127 | #define JS_NAN JS_MKVAL(JS_TAG_FLOAT64, 1) 128 | 129 | static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) 130 | { 131 | return JS_MKVAL(JS_TAG_FLOAT64, (int)d); 132 | } 133 | 134 | static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) 135 | { 136 | return 0; 137 | } 138 | 139 | static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int32_t d) 140 | { 141 | return JS_MKVAL(JS_TAG_SHORT_BIG_INT, d); 142 | } 143 | 144 | #elif defined(JS_NAN_BOXING) 145 | 146 | typedef uint64_t JSValue; 147 | 148 | #define JSValueConst JSValue 149 | 150 | #define JS_VALUE_GET_TAG(v) (int)((v) >> 32) 151 | #define JS_VALUE_GET_INT(v) (int)(v) 152 | #define JS_VALUE_GET_BOOL(v) (int)(v) 153 | #define JS_VALUE_GET_SHORT_BIG_INT(v) (int)(v) 154 | #define JS_VALUE_GET_PTR(v) (void *)(intptr_t)(v) 155 | 156 | #define JS_MKVAL(tag, val) (((uint64_t)(tag) << 32) | (uint32_t)(val)) 157 | #define JS_MKPTR(tag, ptr) (((uint64_t)(tag) << 32) | (uintptr_t)(ptr)) 158 | 159 | #define JS_FLOAT64_TAG_ADDEND (0x7ff80000 - JS_TAG_FIRST + 1) /* quiet NaN encoding */ 160 | 161 | static inline double JS_VALUE_GET_FLOAT64(JSValue v) 162 | { 163 | union { 164 | JSValue v; 165 | double d; 166 | } u; 167 | u.v = v; 168 | u.v += (uint64_t)JS_FLOAT64_TAG_ADDEND << 32; 169 | return u.d; 170 | } 171 | 172 | #define JS_NAN (0x7ff8000000000000 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32)) 173 | 174 | static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) 175 | { 176 | union { 177 | double d; 178 | uint64_t u64; 179 | } u; 180 | JSValue v; 181 | u.d = d; 182 | /* normalize NaN */ 183 | if (js_unlikely((u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000)) 184 | v = JS_NAN; 185 | else 186 | v = u.u64 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32); 187 | return v; 188 | } 189 | 190 | #define JS_TAG_IS_FLOAT64(tag) ((unsigned)((tag) - JS_TAG_FIRST) >= (JS_TAG_FLOAT64 - JS_TAG_FIRST)) 191 | 192 | /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ 193 | static inline int JS_VALUE_GET_NORM_TAG(JSValue v) 194 | { 195 | uint32_t tag; 196 | tag = JS_VALUE_GET_TAG(v); 197 | if (JS_TAG_IS_FLOAT64(tag)) 198 | return JS_TAG_FLOAT64; 199 | else 200 | return tag; 201 | } 202 | 203 | static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) 204 | { 205 | uint32_t tag; 206 | tag = JS_VALUE_GET_TAG(v); 207 | return tag == (JS_NAN >> 32); 208 | } 209 | 210 | static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int32_t d) 211 | { 212 | return JS_MKVAL(JS_TAG_SHORT_BIG_INT, d); 213 | } 214 | 215 | #else /* !JS_NAN_BOXING */ 216 | 217 | typedef union JSValueUnion { 218 | int32_t int32; 219 | double float64; 220 | void *ptr; 221 | #if JS_SHORT_BIG_INT_BITS == 32 222 | int32_t short_big_int; 223 | #else 224 | int64_t short_big_int; 225 | #endif 226 | } JSValueUnion; 227 | 228 | typedef struct JSValue { 229 | JSValueUnion u; 230 | int64_t tag; 231 | } JSValue; 232 | 233 | #define JSValueConst JSValue 234 | 235 | #define JS_VALUE_GET_TAG(v) ((int32_t)(v).tag) 236 | /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ 237 | #define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v) 238 | #define JS_VALUE_GET_INT(v) ((v).u.int32) 239 | #define JS_VALUE_GET_BOOL(v) ((v).u.int32) 240 | #define JS_VALUE_GET_FLOAT64(v) ((v).u.float64) 241 | #define JS_VALUE_GET_SHORT_BIG_INT(v) ((v).u.short_big_int) 242 | #define JS_VALUE_GET_PTR(v) ((v).u.ptr) 243 | 244 | #define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag } 245 | #define JS_MKPTR(tag, p) (JSValue){ (JSValueUnion){ .ptr = p }, tag } 246 | 247 | #define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64) 248 | 249 | #define JS_NAN (JSValue){ .u.float64 = JS_FLOAT64_NAN, JS_TAG_FLOAT64 } 250 | 251 | static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) 252 | { 253 | JSValue v; 254 | v.tag = JS_TAG_FLOAT64; 255 | v.u.float64 = d; 256 | return v; 257 | } 258 | 259 | static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) 260 | { 261 | union { 262 | double d; 263 | uint64_t u64; 264 | } u; 265 | if (v.tag != JS_TAG_FLOAT64) 266 | return 0; 267 | u.d = v.u.float64; 268 | return (u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000; 269 | } 270 | 271 | static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int64_t d) 272 | { 273 | JSValue v; 274 | v.tag = JS_TAG_SHORT_BIG_INT; 275 | v.u.short_big_int = d; 276 | return v; 277 | } 278 | 279 | #endif /* !JS_NAN_BOXING */ 280 | 281 | #define JS_VALUE_IS_BOTH_INT(v1, v2) ((JS_VALUE_GET_TAG(v1) | JS_VALUE_GET_TAG(v2)) == 0) 282 | #define JS_VALUE_IS_BOTH_FLOAT(v1, v2) (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v1)) && JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v2))) 283 | 284 | #define JS_VALUE_HAS_REF_COUNT(v) ((unsigned)JS_VALUE_GET_TAG(v) >= (unsigned)JS_TAG_FIRST) 285 | 286 | /* special values */ 287 | #define JS_NULL JS_MKVAL(JS_TAG_NULL, 0) 288 | #define JS_UNDEFINED JS_MKVAL(JS_TAG_UNDEFINED, 0) 289 | #define JS_FALSE JS_MKVAL(JS_TAG_BOOL, 0) 290 | #define JS_TRUE JS_MKVAL(JS_TAG_BOOL, 1) 291 | #define JS_EXCEPTION JS_MKVAL(JS_TAG_EXCEPTION, 0) 292 | #define JS_UNINITIALIZED JS_MKVAL(JS_TAG_UNINITIALIZED, 0) 293 | 294 | /* flags for object properties */ 295 | #define JS_PROP_CONFIGURABLE (1 << 0) 296 | #define JS_PROP_WRITABLE (1 << 1) 297 | #define JS_PROP_ENUMERABLE (1 << 2) 298 | #define JS_PROP_C_W_E (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE | JS_PROP_ENUMERABLE) 299 | #define JS_PROP_LENGTH (1 << 3) /* used internally in Arrays */ 300 | #define JS_PROP_TMASK (3 << 4) /* mask for NORMAL, GETSET, VARREF, AUTOINIT */ 301 | #define JS_PROP_NORMAL (0 << 4) 302 | #define JS_PROP_GETSET (1 << 4) 303 | #define JS_PROP_VARREF (2 << 4) /* used internally */ 304 | #define JS_PROP_AUTOINIT (3 << 4) /* used internally */ 305 | 306 | /* flags for JS_DefineProperty */ 307 | #define JS_PROP_HAS_SHIFT 8 308 | #define JS_PROP_HAS_CONFIGURABLE (1 << 8) 309 | #define JS_PROP_HAS_WRITABLE (1 << 9) 310 | #define JS_PROP_HAS_ENUMERABLE (1 << 10) 311 | #define JS_PROP_HAS_GET (1 << 11) 312 | #define JS_PROP_HAS_SET (1 << 12) 313 | #define JS_PROP_HAS_VALUE (1 << 13) 314 | 315 | /* throw an exception if false would be returned 316 | (JS_DefineProperty/JS_SetProperty) */ 317 | #define JS_PROP_THROW (1 << 14) 318 | /* throw an exception if false would be returned in strict mode 319 | (JS_SetProperty) */ 320 | #define JS_PROP_THROW_STRICT (1 << 15) 321 | 322 | #define JS_PROP_NO_ADD (1 << 16) /* internal use */ 323 | #define JS_PROP_NO_EXOTIC (1 << 17) /* internal use */ 324 | 325 | #ifndef JS_DEFAULT_STACK_SIZE 326 | #define JS_DEFAULT_STACK_SIZE (1024 * 1024) 327 | #endif 328 | 329 | /* JS_Eval() flags */ 330 | #define JS_EVAL_TYPE_GLOBAL (0 << 0) /* global code (default) */ 331 | #define JS_EVAL_TYPE_MODULE (1 << 0) /* module code */ 332 | #define JS_EVAL_TYPE_DIRECT (2 << 0) /* direct call (internal use) */ 333 | #define JS_EVAL_TYPE_INDIRECT (3 << 0) /* indirect call (internal use) */ 334 | #define JS_EVAL_TYPE_MASK (3 << 0) 335 | 336 | #define JS_EVAL_FLAG_STRICT (1 << 3) /* force 'strict' mode */ 337 | /* compile but do not run. The result is an object with a 338 | JS_TAG_FUNCTION_BYTECODE or JS_TAG_MODULE tag. It can be executed 339 | with JS_EvalFunction(). */ 340 | #define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5) 341 | /* don't include the stack frames before this eval in the Error() backtraces */ 342 | #define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6) 343 | /* allow top-level await in normal script. JS_Eval() returns a 344 | promise. Only allowed with JS_EVAL_TYPE_GLOBAL */ 345 | #define JS_EVAL_FLAG_ASYNC (1 << 7) 346 | 347 | typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); 348 | typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); 349 | typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data); 350 | 351 | typedef struct JSMallocState { 352 | size_t malloc_count; 353 | size_t malloc_size; 354 | size_t malloc_limit; 355 | void *opaque; /* user opaque */ 356 | } JSMallocState; 357 | 358 | typedef struct JSMallocFunctions { 359 | void *(*js_malloc)(JSMallocState *s, size_t size); 360 | void (*js_free)(JSMallocState *s, void *ptr); 361 | void *(*js_realloc)(JSMallocState *s, void *ptr, size_t size); 362 | size_t (*js_malloc_usable_size)(const void *ptr); 363 | } JSMallocFunctions; 364 | 365 | typedef struct JSGCObjectHeader JSGCObjectHeader; 366 | 367 | JSRuntime *JS_NewRuntime(void); 368 | /* info lifetime must exceed that of rt */ 369 | void JS_SetRuntimeInfo(JSRuntime *rt, const char *info); 370 | void JS_SetMemoryLimit(JSRuntime *rt, size_t limit); 371 | void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); 372 | /* use 0 to disable maximum stack size check */ 373 | void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size); 374 | /* should be called when changing thread to update the stack top value 375 | used to check stack overflow. */ 376 | void JS_UpdateStackTop(JSRuntime *rt); 377 | JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque); 378 | void JS_FreeRuntime(JSRuntime *rt); 379 | void *JS_GetRuntimeOpaque(JSRuntime *rt); 380 | void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque); 381 | typedef void JS_MarkFunc(JSRuntime *rt, JSGCObjectHeader *gp); 382 | void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); 383 | void JS_RunGC(JSRuntime *rt); 384 | JS_BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj); 385 | 386 | JSContext *JS_NewContext(JSRuntime *rt); 387 | void JS_FreeContext(JSContext *s); 388 | JSContext *JS_DupContext(JSContext *ctx); 389 | void *JS_GetContextOpaque(JSContext *ctx); 390 | void JS_SetContextOpaque(JSContext *ctx, void *opaque); 391 | JSRuntime *JS_GetRuntime(JSContext *ctx); 392 | void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj); 393 | JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id); 394 | 395 | /* the following functions are used to select the intrinsic object to 396 | save memory */ 397 | JSContext *JS_NewContextRaw(JSRuntime *rt); 398 | void JS_AddIntrinsicBaseObjects(JSContext *ctx); 399 | void JS_AddIntrinsicDate(JSContext *ctx); 400 | void JS_AddIntrinsicEval(JSContext *ctx); 401 | void JS_AddIntrinsicStringNormalize(JSContext *ctx); 402 | void JS_AddIntrinsicRegExpCompiler(JSContext *ctx); 403 | void JS_AddIntrinsicRegExp(JSContext *ctx); 404 | void JS_AddIntrinsicJSON(JSContext *ctx); 405 | void JS_AddIntrinsicProxy(JSContext *ctx); 406 | void JS_AddIntrinsicMapSet(JSContext *ctx); 407 | void JS_AddIntrinsicTypedArrays(JSContext *ctx); 408 | void JS_AddIntrinsicPromise(JSContext *ctx); 409 | void JS_AddIntrinsicWeakRef(JSContext *ctx); 410 | 411 | JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val, 412 | int argc, JSValueConst *argv); 413 | 414 | void *js_malloc_rt(JSRuntime *rt, size_t size); 415 | void js_free_rt(JSRuntime *rt, void *ptr); 416 | void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size); 417 | size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr); 418 | void *js_mallocz_rt(JSRuntime *rt, size_t size); 419 | 420 | void *js_malloc(JSContext *ctx, size_t size); 421 | void js_free(JSContext *ctx, void *ptr); 422 | void *js_realloc(JSContext *ctx, void *ptr, size_t size); 423 | size_t js_malloc_usable_size(JSContext *ctx, const void *ptr); 424 | void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack); 425 | void *js_mallocz(JSContext *ctx, size_t size); 426 | char *js_strdup(JSContext *ctx, const char *str); 427 | char *js_strndup(JSContext *ctx, const char *s, size_t n); 428 | 429 | typedef struct JSMemoryUsage { 430 | int64_t malloc_size, malloc_limit, memory_used_size; 431 | int64_t malloc_count; 432 | int64_t memory_used_count; 433 | int64_t atom_count, atom_size; 434 | int64_t str_count, str_size; 435 | int64_t obj_count, obj_size; 436 | int64_t prop_count, prop_size; 437 | int64_t shape_count, shape_size; 438 | int64_t js_func_count, js_func_size, js_func_code_size; 439 | int64_t js_func_pc2line_count, js_func_pc2line_size; 440 | int64_t c_func_count, array_count; 441 | int64_t fast_array_count, fast_array_elements; 442 | int64_t binary_object_count, binary_object_size; 443 | } JSMemoryUsage; 444 | 445 | void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s); 446 | void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt); 447 | 448 | /* atom support */ 449 | #define JS_ATOM_NULL 0 450 | 451 | JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len); 452 | JSAtom JS_NewAtom(JSContext *ctx, const char *str); 453 | JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n); 454 | JSAtom JS_DupAtom(JSContext *ctx, JSAtom v); 455 | void JS_FreeAtom(JSContext *ctx, JSAtom v); 456 | void JS_FreeAtomRT(JSRuntime *rt, JSAtom v); 457 | JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom); 458 | JSValue JS_AtomToString(JSContext *ctx, JSAtom atom); 459 | const char *JS_AtomToCStringLen(JSContext *ctx, size_t *plen, JSAtom atom); 460 | static inline const char *JS_AtomToCString(JSContext *ctx, JSAtom atom) 461 | { 462 | return JS_AtomToCStringLen(ctx, NULL, atom); 463 | } 464 | JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val); 465 | 466 | /* object class support */ 467 | 468 | typedef struct JSPropertyEnum { 469 | JS_BOOL is_enumerable; 470 | JSAtom atom; 471 | } JSPropertyEnum; 472 | 473 | typedef struct JSPropertyDescriptor { 474 | int flags; 475 | JSValue value; 476 | JSValue getter; 477 | JSValue setter; 478 | } JSPropertyDescriptor; 479 | 480 | typedef struct JSClassExoticMethods { 481 | /* Return -1 if exception (can only happen in case of Proxy object), 482 | FALSE if the property does not exists, TRUE if it exists. If 1 is 483 | returned, the property descriptor 'desc' is filled if != NULL. */ 484 | int (*get_own_property)(JSContext *ctx, JSPropertyDescriptor *desc, 485 | JSValueConst obj, JSAtom prop); 486 | /* '*ptab' should hold the '*plen' property keys. Return 0 if OK, 487 | -1 if exception. The 'is_enumerable' field is ignored. 488 | */ 489 | int (*get_own_property_names)(JSContext *ctx, JSPropertyEnum **ptab, 490 | uint32_t *plen, 491 | JSValueConst obj); 492 | /* return < 0 if exception, or TRUE/FALSE */ 493 | int (*delete_property)(JSContext *ctx, JSValueConst obj, JSAtom prop); 494 | /* return < 0 if exception or TRUE/FALSE */ 495 | int (*define_own_property)(JSContext *ctx, JSValueConst this_obj, 496 | JSAtom prop, JSValueConst val, 497 | JSValueConst getter, JSValueConst setter, 498 | int flags); 499 | /* The following methods can be emulated with the previous ones, 500 | so they are usually not needed */ 501 | /* return < 0 if exception or TRUE/FALSE */ 502 | int (*has_property)(JSContext *ctx, JSValueConst obj, JSAtom atom); 503 | JSValue (*get_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, 504 | JSValueConst receiver); 505 | /* return < 0 if exception or TRUE/FALSE */ 506 | int (*set_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, 507 | JSValueConst value, JSValueConst receiver, int flags); 508 | 509 | /* To get a consistent object behavior when get_prototype != NULL, 510 | get_property, set_property and set_prototype must be != NULL 511 | and the object must be created with a JS_NULL prototype. */ 512 | JSValue (*get_prototype)(JSContext *ctx, JSValueConst obj); 513 | /* return < 0 if exception or TRUE/FALSE */ 514 | int (*set_prototype)(JSContext *ctx, JSValueConst obj, JSValueConst proto_val); 515 | /* return < 0 if exception or TRUE/FALSE */ 516 | int (*is_extensible)(JSContext *ctx, JSValueConst obj); 517 | /* return < 0 if exception or TRUE/FALSE */ 518 | int (*prevent_extensions)(JSContext *ctx, JSValueConst obj); 519 | } JSClassExoticMethods; 520 | 521 | typedef void JSClassFinalizer(JSRuntime *rt, JSValue val); 522 | typedef void JSClassGCMark(JSRuntime *rt, JSValueConst val, 523 | JS_MarkFunc *mark_func); 524 | #define JS_CALL_FLAG_CONSTRUCTOR (1 << 0) 525 | typedef JSValue JSClassCall(JSContext *ctx, JSValueConst func_obj, 526 | JSValueConst this_val, int argc, JSValueConst *argv, 527 | int flags); 528 | 529 | typedef struct JSClassDef { 530 | const char *class_name; 531 | JSClassFinalizer *finalizer; 532 | JSClassGCMark *gc_mark; 533 | /* if call != NULL, the object is a function. If (flags & 534 | JS_CALL_FLAG_CONSTRUCTOR) != 0, the function is called as a 535 | constructor. In this case, 'this_val' is new.target. A 536 | constructor call only happens if the object constructor bit is 537 | set (see JS_SetConstructorBit()). */ 538 | JSClassCall *call; 539 | /* XXX: suppress this indirection ? It is here only to save memory 540 | because only a few classes need these methods */ 541 | JSClassExoticMethods *exotic; 542 | } JSClassDef; 543 | 544 | #define JS_INVALID_CLASS_ID 0 545 | JSClassID JS_NewClassID(JSClassID *pclass_id); 546 | /* Returns the class ID if `v` is an object, otherwise returns JS_INVALID_CLASS_ID. */ 547 | JSClassID JS_GetClassID(JSValueConst v); 548 | int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def); 549 | int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id); 550 | 551 | /* value handling */ 552 | 553 | static js_force_inline JSValue JS_NewBool(JSContext *ctx, JS_BOOL val) 554 | { 555 | return JS_MKVAL(JS_TAG_BOOL, (val != 0)); 556 | } 557 | 558 | static js_force_inline JSValue JS_NewInt32(JSContext *ctx, int32_t val) 559 | { 560 | return JS_MKVAL(JS_TAG_INT, val); 561 | } 562 | 563 | static js_force_inline JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val) 564 | { 565 | return JS_MKVAL(JS_TAG_CATCH_OFFSET, val); 566 | } 567 | 568 | static js_force_inline JSValue JS_NewInt64(JSContext *ctx, int64_t val) 569 | { 570 | JSValue v; 571 | if (val == (int32_t)val) { 572 | v = JS_NewInt32(ctx, val); 573 | } else { 574 | v = __JS_NewFloat64(ctx, val); 575 | } 576 | return v; 577 | } 578 | 579 | static js_force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val) 580 | { 581 | JSValue v; 582 | if (val <= 0x7fffffff) { 583 | v = JS_NewInt32(ctx, val); 584 | } else { 585 | v = __JS_NewFloat64(ctx, val); 586 | } 587 | return v; 588 | } 589 | 590 | JSValue JS_NewBigInt64(JSContext *ctx, int64_t v); 591 | JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v); 592 | 593 | static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double d) 594 | { 595 | int32_t val; 596 | union { 597 | double d; 598 | uint64_t u; 599 | } u, t; 600 | if (d >= INT32_MIN && d <= INT32_MAX) { 601 | u.d = d; 602 | val = (int32_t)d; 603 | t.d = val; 604 | /* -0 cannot be represented as integer, so we compare the bit 605 | representation */ 606 | if (u.u == t.u) 607 | return JS_MKVAL(JS_TAG_INT, val); 608 | } 609 | return __JS_NewFloat64(ctx, d); 610 | } 611 | 612 | static inline JS_BOOL JS_IsNumber(JSValueConst v) 613 | { 614 | int tag = JS_VALUE_GET_TAG(v); 615 | return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag); 616 | } 617 | 618 | static inline JS_BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v) 619 | { 620 | int tag = JS_VALUE_GET_TAG(v); 621 | return tag == JS_TAG_BIG_INT || tag == JS_TAG_SHORT_BIG_INT; 622 | } 623 | 624 | static inline JS_BOOL JS_IsBool(JSValueConst v) 625 | { 626 | return JS_VALUE_GET_TAG(v) == JS_TAG_BOOL; 627 | } 628 | 629 | static inline JS_BOOL JS_IsNull(JSValueConst v) 630 | { 631 | return JS_VALUE_GET_TAG(v) == JS_TAG_NULL; 632 | } 633 | 634 | static inline JS_BOOL JS_IsUndefined(JSValueConst v) 635 | { 636 | return JS_VALUE_GET_TAG(v) == JS_TAG_UNDEFINED; 637 | } 638 | 639 | static inline JS_BOOL JS_IsException(JSValueConst v) 640 | { 641 | return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_EXCEPTION); 642 | } 643 | 644 | static inline JS_BOOL JS_IsUninitialized(JSValueConst v) 645 | { 646 | return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_UNINITIALIZED); 647 | } 648 | 649 | static inline JS_BOOL JS_IsString(JSValueConst v) 650 | { 651 | return JS_VALUE_GET_TAG(v) == JS_TAG_STRING || 652 | JS_VALUE_GET_TAG(v) == JS_TAG_STRING_ROPE; 653 | } 654 | 655 | static inline JS_BOOL JS_IsSymbol(JSValueConst v) 656 | { 657 | return JS_VALUE_GET_TAG(v) == JS_TAG_SYMBOL; 658 | } 659 | 660 | static inline JS_BOOL JS_IsObject(JSValueConst v) 661 | { 662 | return JS_VALUE_GET_TAG(v) == JS_TAG_OBJECT; 663 | } 664 | 665 | JSValue JS_Throw(JSContext *ctx, JSValue obj); 666 | void JS_SetUncatchableException(JSContext *ctx, JS_BOOL flag); 667 | JSValue JS_GetException(JSContext *ctx); 668 | JS_BOOL JS_HasException(JSContext *ctx); 669 | JS_BOOL JS_IsError(JSContext *ctx, JSValueConst val); 670 | JSValue JS_NewError(JSContext *ctx); 671 | JSValue __js_printf_like(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...); 672 | JSValue __js_printf_like(2, 3) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...); 673 | JSValue __js_printf_like(2, 3) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...); 674 | JSValue __js_printf_like(2, 3) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...); 675 | JSValue __js_printf_like(2, 3) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...); 676 | JSValue JS_ThrowOutOfMemory(JSContext *ctx); 677 | 678 | void __JS_FreeValue(JSContext *ctx, JSValue v); 679 | static inline void JS_FreeValue(JSContext *ctx, JSValue v) 680 | { 681 | if (JS_VALUE_HAS_REF_COUNT(v)) { 682 | JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); 683 | if (--p->ref_count <= 0) { 684 | __JS_FreeValue(ctx, v); 685 | } 686 | } 687 | } 688 | void __JS_FreeValueRT(JSRuntime *rt, JSValue v); 689 | static inline void JS_FreeValueRT(JSRuntime *rt, JSValue v) 690 | { 691 | if (JS_VALUE_HAS_REF_COUNT(v)) { 692 | JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); 693 | if (--p->ref_count <= 0) { 694 | __JS_FreeValueRT(rt, v); 695 | } 696 | } 697 | } 698 | 699 | static inline JSValue JS_DupValue(JSContext *ctx, JSValueConst v) 700 | { 701 | if (JS_VALUE_HAS_REF_COUNT(v)) { 702 | JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); 703 | p->ref_count++; 704 | } 705 | return (JSValue)v; 706 | } 707 | 708 | static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v) 709 | { 710 | if (JS_VALUE_HAS_REF_COUNT(v)) { 711 | JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); 712 | p->ref_count++; 713 | } 714 | return (JSValue)v; 715 | } 716 | 717 | JS_BOOL JS_StrictEq(JSContext *ctx, JSValueConst op1, JSValueConst op2); 718 | JS_BOOL JS_SameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2); 719 | JS_BOOL JS_SameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2); 720 | 721 | int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */ 722 | int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val); 723 | static inline int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val) 724 | { 725 | return JS_ToInt32(ctx, (int32_t*)pres, val); 726 | } 727 | int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val); 728 | int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val); 729 | int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val); 730 | /* return an exception if 'val' is a Number */ 731 | int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val); 732 | /* same as JS_ToInt64() but allow BigInt */ 733 | int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val); 734 | 735 | JSValue JS_NewStringLen(JSContext *ctx, const char *str1, size_t len1); 736 | static inline JSValue JS_NewString(JSContext *ctx, const char *str) 737 | { 738 | return JS_NewStringLen(ctx, str, strlen(str)); 739 | } 740 | JSValue JS_NewAtomString(JSContext *ctx, const char *str); 741 | JSValue JS_ToString(JSContext *ctx, JSValueConst val); 742 | JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val); 743 | const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, JS_BOOL cesu8); 744 | static inline const char *JS_ToCStringLen(JSContext *ctx, size_t *plen, JSValueConst val1) 745 | { 746 | return JS_ToCStringLen2(ctx, plen, val1, 0); 747 | } 748 | static inline const char *JS_ToCString(JSContext *ctx, JSValueConst val1) 749 | { 750 | return JS_ToCStringLen2(ctx, NULL, val1, 0); 751 | } 752 | void JS_FreeCString(JSContext *ctx, const char *ptr); 753 | 754 | JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto, JSClassID class_id); 755 | JSValue JS_NewObjectClass(JSContext *ctx, int class_id); 756 | JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto); 757 | JSValue JS_NewObject(JSContext *ctx); 758 | 759 | JS_BOOL JS_IsFunction(JSContext* ctx, JSValueConst val); 760 | JS_BOOL JS_IsConstructor(JSContext* ctx, JSValueConst val); 761 | JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val); 762 | 763 | JSValue JS_NewArray(JSContext *ctx); 764 | int JS_IsArray(JSContext *ctx, JSValueConst val); 765 | 766 | JSValue JS_NewDate(JSContext *ctx, double epoch_ms); 767 | 768 | JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, 769 | JSAtom prop, JSValueConst receiver, 770 | JS_BOOL throw_ref_error); 771 | static js_force_inline JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj, 772 | JSAtom prop) 773 | { 774 | return JS_GetPropertyInternal(ctx, this_obj, prop, this_obj, 0); 775 | } 776 | JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj, 777 | const char *prop); 778 | JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj, 779 | uint32_t idx); 780 | 781 | int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, 782 | JSAtom prop, JSValue val, JSValueConst this_obj, 783 | int flags); 784 | static inline int JS_SetProperty(JSContext *ctx, JSValueConst this_obj, 785 | JSAtom prop, JSValue val) 786 | { 787 | return JS_SetPropertyInternal(ctx, this_obj, prop, val, this_obj, JS_PROP_THROW); 788 | } 789 | int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj, 790 | uint32_t idx, JSValue val); 791 | int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj, 792 | int64_t idx, JSValue val); 793 | int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj, 794 | const char *prop, JSValue val); 795 | int JS_HasProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop); 796 | int JS_IsExtensible(JSContext *ctx, JSValueConst obj); 797 | int JS_PreventExtensions(JSContext *ctx, JSValueConst obj); 798 | int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags); 799 | int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val); 800 | JSValue JS_GetPrototype(JSContext *ctx, JSValueConst val); 801 | 802 | #define JS_GPN_STRING_MASK (1 << 0) 803 | #define JS_GPN_SYMBOL_MASK (1 << 1) 804 | #define JS_GPN_PRIVATE_MASK (1 << 2) 805 | /* only include the enumerable properties */ 806 | #define JS_GPN_ENUM_ONLY (1 << 4) 807 | /* set theJSPropertyEnum.is_enumerable field */ 808 | #define JS_GPN_SET_ENUM (1 << 5) 809 | 810 | int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, 811 | uint32_t *plen, JSValueConst obj, int flags); 812 | void JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab, 813 | uint32_t len); 814 | int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc, 815 | JSValueConst obj, JSAtom prop); 816 | 817 | JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, 818 | int argc, JSValueConst *argv); 819 | JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom, 820 | int argc, JSValueConst *argv); 821 | JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj, 822 | int argc, JSValueConst *argv); 823 | JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj, 824 | JSValueConst new_target, 825 | int argc, JSValueConst *argv); 826 | JS_BOOL JS_DetectModule(const char *input, size_t input_len); 827 | /* 'input' must be zero terminated i.e. input[input_len] = '\0'. */ 828 | JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len, 829 | const char *filename, int eval_flags); 830 | /* same as JS_Eval() but with an explicit 'this_obj' parameter */ 831 | JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj, 832 | const char *input, size_t input_len, 833 | const char *filename, int eval_flags); 834 | JSValue JS_GetGlobalObject(JSContext *ctx); 835 | int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj); 836 | int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, 837 | JSAtom prop, JSValueConst val, 838 | JSValueConst getter, JSValueConst setter, int flags); 839 | int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj, 840 | JSAtom prop, JSValue val, int flags); 841 | int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj, 842 | uint32_t idx, JSValue val, int flags); 843 | int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj, 844 | const char *prop, JSValue val, int flags); 845 | int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj, 846 | JSAtom prop, JSValue getter, JSValue setter, 847 | int flags); 848 | void JS_SetOpaque(JSValue obj, void *opaque); 849 | void *JS_GetOpaque(JSValueConst obj, JSClassID class_id); 850 | void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id); 851 | void *JS_GetAnyOpaque(JSValueConst obj, JSClassID *class_id); 852 | 853 | /* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */ 854 | JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, 855 | const char *filename); 856 | #define JS_PARSE_JSON_EXT (1 << 0) /* allow extended JSON */ 857 | JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len, 858 | const char *filename, int flags); 859 | JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj, 860 | JSValueConst replacer, JSValueConst space0); 861 | 862 | typedef void JSFreeArrayBufferDataFunc(JSRuntime *rt, void *opaque, void *ptr); 863 | JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len, 864 | JSFreeArrayBufferDataFunc *free_func, void *opaque, 865 | JS_BOOL is_shared); 866 | JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len); 867 | void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj); 868 | uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj); 869 | 870 | typedef enum JSTypedArrayEnum { 871 | JS_TYPED_ARRAY_UINT8C = 0, 872 | JS_TYPED_ARRAY_INT8, 873 | JS_TYPED_ARRAY_UINT8, 874 | JS_TYPED_ARRAY_INT16, 875 | JS_TYPED_ARRAY_UINT16, 876 | JS_TYPED_ARRAY_INT32, 877 | JS_TYPED_ARRAY_UINT32, 878 | JS_TYPED_ARRAY_BIG_INT64, 879 | JS_TYPED_ARRAY_BIG_UINT64, 880 | JS_TYPED_ARRAY_FLOAT16, 881 | JS_TYPED_ARRAY_FLOAT32, 882 | JS_TYPED_ARRAY_FLOAT64, 883 | } JSTypedArrayEnum; 884 | 885 | JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv, 886 | JSTypedArrayEnum array_type); 887 | JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj, 888 | size_t *pbyte_offset, 889 | size_t *pbyte_length, 890 | size_t *pbytes_per_element); 891 | typedef struct { 892 | void *(*sab_alloc)(void *opaque, size_t size); 893 | void (*sab_free)(void *opaque, void *ptr); 894 | void (*sab_dup)(void *opaque, void *ptr); 895 | void *sab_opaque; 896 | } JSSharedArrayBufferFunctions; 897 | void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, 898 | const JSSharedArrayBufferFunctions *sf); 899 | 900 | typedef enum JSPromiseStateEnum { 901 | JS_PROMISE_PENDING, 902 | JS_PROMISE_FULFILLED, 903 | JS_PROMISE_REJECTED, 904 | } JSPromiseStateEnum; 905 | 906 | JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs); 907 | JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise); 908 | JSValue JS_PromiseResult(JSContext *ctx, JSValue promise); 909 | 910 | /* is_handled = TRUE means that the rejection is handled */ 911 | typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise, 912 | JSValueConst reason, 913 | JS_BOOL is_handled, void *opaque); 914 | void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTracker *cb, void *opaque); 915 | void JS_SetHostUnhandledPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTracker *cb, void *opaque); 916 | 917 | /* return != 0 if the JS code needs to be interrupted */ 918 | typedef int JSInterruptHandler(JSRuntime *rt, void *opaque); 919 | void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque); 920 | /* if can_block is TRUE, Atomics.wait() can be used */ 921 | void JS_SetCanBlock(JSRuntime *rt, JS_BOOL can_block); 922 | /* select which debug info is stripped from the compiled code */ 923 | #define JS_STRIP_SOURCE (1 << 0) /* strip source code */ 924 | #define JS_STRIP_DEBUG (1 << 1) /* strip all debug info including source code */ 925 | void JS_SetStripInfo(JSRuntime *rt, int flags); 926 | int JS_GetStripInfo(JSRuntime *rt); 927 | 928 | /* set the [IsHTMLDDA] internal slot */ 929 | void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj); 930 | 931 | typedef struct JSModuleDef JSModuleDef; 932 | 933 | /* return the module specifier (allocated with js_malloc()) or NULL if 934 | exception */ 935 | typedef char *JSModuleNormalizeFunc(JSContext *ctx, 936 | const char *module_base_name, 937 | const char *module_name, void *opaque); 938 | typedef JSModuleDef *JSModuleLoaderFunc(JSContext *ctx, 939 | const char *module_name, void *opaque); 940 | typedef JSModuleDef *JSModuleLoaderFunc2(JSContext *ctx, 941 | const char *module_name, void *opaque, 942 | JSValueConst attributes); 943 | /* return -1 if exception, 0 if OK */ 944 | typedef int JSModuleCheckSupportedImportAttributes(JSContext *ctx, void *opaque, 945 | JSValueConst attributes); 946 | 947 | /* module_normalize = NULL is allowed and invokes the default module 948 | filename normalizer */ 949 | void JS_SetModuleLoaderFunc(JSRuntime *rt, 950 | JSModuleNormalizeFunc *module_normalize, 951 | JSModuleLoaderFunc *module_loader, void *opaque); 952 | /* same as JS_SetModuleLoaderFunc but with attributes. if 953 | module_check_attrs = NULL, no attribute checking is done. */ 954 | void JS_SetModuleLoaderFunc2(JSRuntime *rt, 955 | JSModuleNormalizeFunc *module_normalize, 956 | JSModuleLoaderFunc2 *module_loader, 957 | JSModuleCheckSupportedImportAttributes *module_check_attrs, 958 | void *opaque); 959 | /* return the import.meta object of a module */ 960 | JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m); 961 | JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m); 962 | JSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m); 963 | 964 | /* JS Job support */ 965 | 966 | typedef JSValue JSJobFunc(JSContext *ctx, int argc, JSValueConst *argv); 967 | int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, int argc, JSValueConst *argv); 968 | 969 | JS_BOOL JS_IsJobPending(JSRuntime *rt); 970 | int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx); 971 | 972 | /* Object Writer/Reader (currently only used to handle precompiled code) */ 973 | #define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */ 974 | #define JS_WRITE_OBJ_BSWAP (1 << 1) /* byte swapped output */ 975 | #define JS_WRITE_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */ 976 | #define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to 977 | encode arbitrary object 978 | graph */ 979 | uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj, 980 | int flags); 981 | uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj, 982 | int flags, uint8_t ***psab_tab, size_t *psab_tab_len); 983 | 984 | #define JS_READ_OBJ_BYTECODE (1 << 0) /* allow function/module */ 985 | #define JS_READ_OBJ_ROM_DATA (1 << 1) /* avoid duplicating 'buf' data */ 986 | #define JS_READ_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */ 987 | #define JS_READ_OBJ_REFERENCE (1 << 3) /* allow object references */ 988 | JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, 989 | int flags); 990 | /* instantiate and evaluate a bytecode function. Only used when 991 | reading a script or module with JS_ReadObject() */ 992 | JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj); 993 | /* load the dependencies of the module 'obj'. Useful when JS_ReadObject() 994 | returns a module. */ 995 | int JS_ResolveModule(JSContext *ctx, JSValueConst obj); 996 | 997 | /* only exported for os.Worker() */ 998 | JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels); 999 | /* only exported for os.Worker() */ 1000 | JSValue JS_LoadModule(JSContext *ctx, const char *basename, 1001 | const char *filename); 1002 | 1003 | /* C function definition */ 1004 | typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */ 1005 | JS_CFUNC_generic, 1006 | JS_CFUNC_generic_magic, 1007 | JS_CFUNC_constructor, 1008 | JS_CFUNC_constructor_magic, 1009 | JS_CFUNC_constructor_or_func, 1010 | JS_CFUNC_constructor_or_func_magic, 1011 | JS_CFUNC_f_f, 1012 | JS_CFUNC_f_f_f, 1013 | JS_CFUNC_getter, 1014 | JS_CFUNC_setter, 1015 | JS_CFUNC_getter_magic, 1016 | JS_CFUNC_setter_magic, 1017 | JS_CFUNC_iterator_next, 1018 | } JSCFunctionEnum; 1019 | 1020 | typedef union JSCFunctionType { 1021 | JSCFunction *generic; 1022 | JSValue (*generic_magic)(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); 1023 | JSCFunction *constructor; 1024 | JSValue (*constructor_magic)(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv, int magic); 1025 | JSCFunction *constructor_or_func; 1026 | double (*f_f)(double); 1027 | double (*f_f_f)(double, double); 1028 | JSValue (*getter)(JSContext *ctx, JSValueConst this_val); 1029 | JSValue (*setter)(JSContext *ctx, JSValueConst this_val, JSValueConst val); 1030 | JSValue (*getter_magic)(JSContext *ctx, JSValueConst this_val, int magic); 1031 | JSValue (*setter_magic)(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic); 1032 | JSValue (*iterator_next)(JSContext *ctx, JSValueConst this_val, 1033 | int argc, JSValueConst *argv, int *pdone, int magic); 1034 | } JSCFunctionType; 1035 | 1036 | JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func, 1037 | const char *name, 1038 | int length, JSCFunctionEnum cproto, int magic); 1039 | JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, 1040 | int length, int magic, int data_len, 1041 | JSValueConst *data); 1042 | 1043 | static inline JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, const char *name, 1044 | int length) 1045 | { 1046 | return JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_generic, 0); 1047 | } 1048 | 1049 | static inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *func, 1050 | const char *name, 1051 | int length, JSCFunctionEnum cproto, int magic) 1052 | { 1053 | return JS_NewCFunction2(ctx, (JSCFunction *)func, name, length, cproto, magic); 1054 | } 1055 | void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, 1056 | JSValueConst proto); 1057 | 1058 | /* C property definition */ 1059 | 1060 | typedef struct JSCFunctionListEntry { 1061 | const char *name; 1062 | uint8_t prop_flags; 1063 | uint8_t def_type; 1064 | int16_t magic; 1065 | union { 1066 | struct { 1067 | uint8_t length; /* XXX: should move outside union */ 1068 | uint8_t cproto; /* XXX: should move outside union */ 1069 | JSCFunctionType cfunc; 1070 | } func; 1071 | struct { 1072 | JSCFunctionType get; 1073 | JSCFunctionType set; 1074 | } getset; 1075 | struct { 1076 | const char *name; 1077 | int base; 1078 | } alias; 1079 | struct { 1080 | const struct JSCFunctionListEntry *tab; 1081 | int len; 1082 | } prop_list; 1083 | const char *str; 1084 | int32_t i32; 1085 | int64_t i64; 1086 | double f64; 1087 | } u; 1088 | } JSCFunctionListEntry; 1089 | 1090 | #define JS_DEF_CFUNC 0 1091 | #define JS_DEF_CGETSET 1 1092 | #define JS_DEF_CGETSET_MAGIC 2 1093 | #define JS_DEF_PROP_STRING 3 1094 | #define JS_DEF_PROP_INT32 4 1095 | #define JS_DEF_PROP_INT64 5 1096 | #define JS_DEF_PROP_DOUBLE 6 1097 | #define JS_DEF_PROP_UNDEFINED 7 1098 | #define JS_DEF_OBJECT 8 1099 | #define JS_DEF_ALIAS 9 1100 | 1101 | /* Note: c++ does not like nested designators */ 1102 | #define JS_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } } 1103 | #define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } } } 1104 | #define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } } } 1105 | #define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } } } 1106 | #define JS_CGETSET_DEF(name, fgetter, fsetter) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET, 0, .u = { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } } 1107 | #define JS_CGETSET_MAGIC_DEF(name, fgetter, fsetter, magic) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET_MAGIC, magic, .u = { .getset = { .get = { .getter_magic = fgetter }, .set = { .setter_magic = fsetter } } } } 1108 | #define JS_PROP_STRING_DEF(name, cstr, prop_flags) { name, prop_flags, JS_DEF_PROP_STRING, 0, .u = { .str = cstr } } 1109 | #define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, .u = { .i32 = val } } 1110 | #define JS_PROP_INT64_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT64, 0, .u = { .i64 = val } } 1111 | #define JS_PROP_DOUBLE_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, .u = { .f64 = val } } 1112 | #define JS_PROP_UNDEFINED_DEF(name, prop_flags) { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, .u = { .i32 = 0 } } 1113 | #define JS_OBJECT_DEF(name, tab, len, prop_flags) { name, prop_flags, JS_DEF_OBJECT, 0, .u = { .prop_list = { tab, len } } } 1114 | #define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, -1 } } } 1115 | #define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, base } } } 1116 | 1117 | int JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj, 1118 | const JSCFunctionListEntry *tab, 1119 | int len); 1120 | 1121 | /* C module definition */ 1122 | 1123 | typedef int JSModuleInitFunc(JSContext *ctx, JSModuleDef *m); 1124 | 1125 | JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str, 1126 | JSModuleInitFunc *func); 1127 | /* can only be called before the module is instantiated */ 1128 | int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *name_str); 1129 | int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m, 1130 | const JSCFunctionListEntry *tab, int len); 1131 | /* can only be called after the module is instantiated */ 1132 | int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name, 1133 | JSValue val); 1134 | int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m, 1135 | const JSCFunctionListEntry *tab, int len); 1136 | /* associate a JSValue to a C module */ 1137 | int JS_SetModulePrivateValue(JSContext *ctx, JSModuleDef *m, JSValue val); 1138 | JSValue JS_GetModulePrivateValue(JSContext *ctx, JSModuleDef *m); 1139 | 1140 | /* debug value output */ 1141 | 1142 | typedef struct { 1143 | JS_BOOL show_hidden : 8; /* only show enumerable properties */ 1144 | JS_BOOL raw_dump : 8; /* avoid doing autoinit and avoid any malloc() call (for internal use) */ 1145 | uint32_t max_depth; /* recurse up to this depth, 0 = no limit */ 1146 | uint32_t max_string_length; /* print no more than this length for 1147 | strings, 0 = no limit */ 1148 | uint32_t max_item_count; /* print no more than this count for 1149 | arrays or objects, 0 = no limit */ 1150 | } JSPrintValueOptions; 1151 | 1152 | typedef void JSPrintValueWrite(void *opaque, const char *buf, size_t len); 1153 | 1154 | void JS_PrintValueSetDefaultOptions(JSPrintValueOptions *options); 1155 | void JS_PrintValueRT(JSRuntime *rt, JSPrintValueWrite *write_func, void *write_opaque, 1156 | JSValueConst val, const JSPrintValueOptions *options); 1157 | void JS_PrintValue(JSContext *ctx, JSPrintValueWrite *write_func, void *write_opaque, 1158 | JSValueConst val, const JSPrintValueOptions *options); 1159 | 1160 | #undef js_unlikely 1161 | #undef js_force_inline 1162 | 1163 | #ifdef __cplusplus 1164 | } /* extern "C" { */ 1165 | #endif 1166 | 1167 | #endif /* QUICKJS_H */ 1168 | --------------------------------------------------------------------------------