aboutsummaryrefslogtreecommitdiffstats
path: root/src/shared
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/CMakeLists.txt1
-rw-r--r--src/shared/json/json.cpp2
-rw-r--r--src/shared/lsp/.clang-tidy3
-rw-r--r--src/shared/lsp/CMakeLists.txt57
-rw-r--r--src/shared/lsp/algorithm.h1518
-rw-r--r--src/shared/lsp/basemessage.cpp188
-rw-r--r--src/shared/lsp/basemessage.h48
-rw-r--r--src/shared/lsp/callhierarchy.cpp28
-rw-r--r--src/shared/lsp/callhierarchy.h108
-rw-r--r--src/shared/lsp/client.cpp17
-rw-r--r--src/shared/lsp/client.h94
-rw-r--r--src/shared/lsp/clientcapabilities.cpp122
-rw-r--r--src/shared/lsp/clientcapabilities.h674
-rw-r--r--src/shared/lsp/completion.cpp59
-rw-r--r--src/shared/lsp/completion.h269
-rw-r--r--src/shared/lsp/diagnostics.cpp13
-rw-r--r--src/shared/lsp/diagnostics.h38
-rw-r--r--src/shared/lsp/filepath.h68
-rw-r--r--src/shared/lsp/initializemessages.cpp137
-rw-r--r--src/shared/lsp/initializemessages.h187
-rw-r--r--src/shared/lsp/jsonkeys.h231
-rw-r--r--src/shared/lsp/jsonobject.cpp28
-rw-r--r--src/shared/lsp/jsonobject.h181
-rw-r--r--src/shared/lsp/jsonrpcmessages.cpp107
-rw-r--r--src/shared/lsp/jsonrpcmessages.h415
-rw-r--r--src/shared/lsp/languagefeatures.cpp399
-rw-r--r--src/shared/lsp/languagefeatures.h836
-rw-r--r--src/shared/lsp/languageserverprotocol_global.h14
-rw-r--r--src/shared/lsp/languageserverprotocoltr.h15
-rw-r--r--src/shared/lsp/link.cpp35
-rw-r--r--src/shared/lsp/link.h78
-rw-r--r--src/shared/lsp/lsp.qbs72
-rw-r--r--src/shared/lsp/lsptypes.cpp364
-rw-r--r--src/shared/lsp/lsptypes.h680
-rw-r--r--src/shared/lsp/lsputils.cpp68
-rw-r--r--src/shared/lsp/lsputils.h160
-rw-r--r--src/shared/lsp/messages.cpp45
-rw-r--r--src/shared/lsp/messages.h93
-rw-r--r--src/shared/lsp/predicates.h110
-rw-r--r--src/shared/lsp/progresssupport.cpp54
-rw-r--r--src/shared/lsp/progresssupport.h152
-rw-r--r--src/shared/lsp/semantictokens.cpp141
-rw-r--r--src/shared/lsp/semantictokens.h230
-rw-r--r--src/shared/lsp/servercapabilities.cpp386
-rw-r--r--src/shared/lsp/servercapabilities.h435
-rw-r--r--src/shared/lsp/shutdownmessages.cpp13
-rw-r--r--src/shared/lsp/shutdownmessages.h29
-rw-r--r--src/shared/lsp/textsynchronization.cpp84
-rw-r--r--src/shared/lsp/textsynchronization.h215
-rw-r--r--src/shared/lsp/textutils.cpp126
-rw-r--r--src/shared/lsp/textutils.h46
-rw-r--r--src/shared/lsp/workspace.cpp82
-rw-r--r--src/shared/lsp/workspace.h245
-rw-r--r--src/shared/quickjs/.clang-format2
-rw-r--r--src/shared/quickjs/.clang-tidy12
-rw-r--r--src/shared/quickjs/CMakeLists.txt1
-rw-r--r--src/shared/quickjs/LICENSE2
-rw-r--r--src/shared/quickjs/cutils.c6
-rw-r--r--src/shared/quickjs/cutils.h90
-rw-r--r--src/shared/quickjs/libbf.c8475
-rw-r--r--src/shared/quickjs/libbf.h543
-rw-r--r--src/shared/quickjs/libregexp-opcode.h5
-rw-r--r--src/shared/quickjs/libregexp.c483
-rw-r--r--src/shared/quickjs/libregexp.h49
-rw-r--r--src/shared/quickjs/libunicode-table.h2650
-rw-r--r--src/shared/quickjs/libunicode.c518
-rw-r--r--src/shared/quickjs/libunicode.h102
-rw-r--r--src/shared/quickjs/list.h11
-rw-r--r--src/shared/quickjs/quickjs-atom.h18
-rw-r--r--src/shared/quickjs/quickjs-opcode.h23
-rw-r--r--src/shared/quickjs/quickjs.c7966
-rw-r--r--src/shared/quickjs/quickjs.diff4061
-rw-r--r--src/shared/quickjs/quickjs.h58
-rw-r--r--src/shared/quickjs/quickjs.qbs5
74 files changed, 26044 insertions, 8836 deletions
diff --git a/src/shared/CMakeLists.txt b/src/shared/CMakeLists.txt
index e517f6489..226dd77ec 100644
--- a/src/shared/CMakeLists.txt
+++ b/src/shared/CMakeLists.txt
@@ -1,3 +1,4 @@
add_subdirectory(json)
+add_subdirectory(lsp)
add_subdirectory(quickjs)
add_subdirectory(variant)
diff --git a/src/shared/json/json.cpp b/src/shared/json/json.cpp
index 7ab85cba5..0ea6e8fd0 100644
--- a/src/shared/json/json.cpp
+++ b/src/shared/json/json.cpp
@@ -3757,7 +3757,7 @@ static void valueToJson(const Base *b, const Value &v, std::string &json, int in
// +2 to format to ensure the expected precision
const int n = std::numeric_limits<double>::digits10 + 2;
char buf[30] = {0};
- std::sprintf(buf, "%.*g", n, d);
+ std::snprintf(buf, sizeof(buf), "%.*g", n, d);
// Hack:
if (buf[0] == '-' && buf[1] == '0' && buf[2] == '\0')
json += "0";
diff --git a/src/shared/lsp/.clang-tidy b/src/shared/lsp/.clang-tidy
new file mode 100644
index 000000000..f451e9596
--- /dev/null
+++ b/src/shared/lsp/.clang-tidy
@@ -0,0 +1,3 @@
+Checks: '-*,misc-definitions-in-headers'
+CheckOptions:
+ - { key: HeaderFileExtensions, value: "x" }
diff --git a/src/shared/lsp/CMakeLists.txt b/src/shared/lsp/CMakeLists.txt
new file mode 100644
index 000000000..1ed95db25
--- /dev/null
+++ b/src/shared/lsp/CMakeLists.txt
@@ -0,0 +1,57 @@
+add_qbs_library(qtclsp
+ STATIC
+ DEPENDS Qt${QT_VERSION_MAJOR}::Core Qt6Core5Compat
+ SOURCES
+ algorithm.h
+ basemessage.cpp
+ basemessage.h
+ callhierarchy.cpp
+ callhierarchy.h
+ client.cpp
+ client.h
+ clientcapabilities.cpp
+ clientcapabilities.h
+ completion.cpp
+ completion.h
+ diagnostics.cpp
+ diagnostics.h
+ initializemessages.cpp
+ initializemessages.h
+ jsonkeys.h
+ jsonobject.cpp
+ jsonobject.h
+ jsonrpcmessages.cpp
+ jsonrpcmessages.h
+ languagefeatures.cpp
+ languagefeatures.h
+ languageserverprotocol_global.h
+ languageserverprotocoltr.h
+ lsptypes.cpp
+ lsptypes.h
+ lsputils.cpp
+ lsputils.h
+ messages.cpp
+ messages.h
+ progresssupport.cpp
+ progresssupport.h
+ semantictokens.cpp
+ semantictokens.h
+ servercapabilities.cpp
+ servercapabilities.h
+ shutdownmessages.cpp
+ shutdownmessages.h
+ textsynchronization.cpp
+ textsynchronization.h
+ textutils.cpp
+ textutils.h
+ workspace.cpp
+ workspace.h
+ )
+target_include_directories(
+ qtclsp
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../lib/corelib
+ PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..
+)
+target_compile_definitions(qtclsp
+ PUBLIC "LANGUAGESERVERPROTOCOL_STATIC_LIBRARY"
+)
diff --git a/src/shared/lsp/algorithm.h b/src/shared/lsp/algorithm.h
new file mode 100644
index 000000000..4c41fb649
--- /dev/null
+++ b/src/shared/lsp/algorithm.h
@@ -0,0 +1,1518 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "predicates.h"
+
+#include <qcompilerdetection.h> // for Q_REQUIRED_RESULT
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <set>
+#include <tuple>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <QHash>
+#include <QObject>
+#include <QSet>
+#include <QStringList>
+
+#include <memory>
+#include <optional>
+#include <type_traits>
+
+namespace lsp::Utils {
+
+/////////////////////////
+// anyOf
+/////////////////////////
+template<typename T, typename F>
+bool anyOf(const T &container, F predicate);
+template<typename T, typename R, typename S>
+bool anyOf(const T &container, R (S::*predicate)() const);
+template<typename T, typename R, typename S>
+bool anyOf(const T &container, R S::*member);
+
+/////////////////////////
+// count
+/////////////////////////
+template<typename T, typename F>
+int count(const T &container, F predicate);
+
+/////////////////////////
+// allOf
+/////////////////////////
+template<typename T, typename F>
+bool allOf(const T &container, F predicate);
+
+/////////////////////////
+// erase
+/////////////////////////
+template<typename T, typename F>
+void erase(T &container, F predicate);
+template<typename T, typename F>
+bool eraseOne(T &container, F predicate);
+
+/////////////////////////
+// contains
+/////////////////////////
+template<typename T, typename F>
+bool contains(const T &container, F function);
+template<typename T, typename R, typename S>
+bool contains(const T &container, R (S::*function)() const);
+template<typename C, typename R, typename S>
+bool contains(const C &container, R S::*member);
+
+/////////////////////////
+// findOr
+/////////////////////////
+template<typename C, typename F>
+Q_REQUIRED_RESULT typename C::value_type findOr(const C &container,
+ typename C::value_type other,
+ F function);
+template<typename T, typename R, typename S>
+Q_REQUIRED_RESULT typename T::value_type findOr(const T &container,
+ typename T::value_type other,
+ R (S::*function)() const);
+template<typename T, typename R, typename S>
+Q_REQUIRED_RESULT typename T::value_type findOr(const T &container,
+ typename T::value_type other,
+ R S::*member);
+
+/////////////////////////
+// findOrDefault
+/////////////////////////
+template<typename C, typename F>
+Q_REQUIRED_RESULT typename std::enable_if_t<std::is_copy_assignable<typename C::value_type>::value,
+ typename C::value_type>
+findOrDefault(const C &container, F function);
+template<typename C, typename R, typename S>
+Q_REQUIRED_RESULT typename std::enable_if_t<std::is_copy_assignable<typename C::value_type>::value,
+ typename C::value_type>
+findOrDefault(const C &container, R (S::*function)() const);
+template<typename C, typename R, typename S>
+Q_REQUIRED_RESULT typename std::enable_if_t<std::is_copy_assignable<typename C::value_type>::value,
+ typename C::value_type>
+findOrDefault(const C &container, R S::*member);
+
+/////////////////////////
+// indexOf
+/////////////////////////
+template<typename C, typename F>
+Q_REQUIRED_RESULT int indexOf(const C &container, F function);
+
+/////////////////////////
+// maxElementOr
+/////////////////////////
+template<typename T>
+typename T::value_type maxElementOr(const T &container, typename T::value_type other);
+
+/////////////////////////
+// filtered
+/////////////////////////
+template<typename C, typename F>
+Q_REQUIRED_RESULT C filtered(const C &container, F predicate);
+template<typename C, typename R, typename S>
+Q_REQUIRED_RESULT C filtered(const C &container, R (S::*predicate)() const);
+
+/////////////////////////
+// partition
+/////////////////////////
+// Recommended usage:
+// C hit;
+// C miss;
+// std::tie(hit, miss) = Utils::partition(container, predicate);
+template<typename C, typename F>
+Q_REQUIRED_RESULT std::tuple<C, C> partition(const C &container, F predicate);
+template<typename C, typename R, typename S>
+Q_REQUIRED_RESULT std::tuple<C, C> partition(const C &container, R (S::*predicate)() const);
+
+/////////////////////////
+// filteredUnique
+/////////////////////////
+template<typename C>
+Q_REQUIRED_RESULT C filteredUnique(const C &container);
+
+/////////////////////////
+// qobject_container_cast
+/////////////////////////
+template<class T, template<typename> class Container, typename Base>
+Container<T> qobject_container_cast(const Container<Base> &container);
+
+/////////////////////////
+// static_container_cast
+/////////////////////////
+template<class T, template<typename> class Container, typename Base>
+Container<T> static_container_cast(const Container<Base> &container);
+
+/////////////////////////
+// sort
+/////////////////////////
+template<typename Container>
+inline void sort(Container &container);
+template<typename Container, typename Predicate>
+inline void sort(Container &container, Predicate p);
+template<typename Container, typename R, typename S>
+inline void sort(Container &container, R S::*member);
+template<typename Container, typename R, typename S>
+inline void sort(Container &container, R (S::*function)() const);
+
+/////////////////////////
+// reverseForeach
+/////////////////////////
+template<typename Container, typename Op>
+inline void reverseForeach(const Container &c, const Op &operation);
+
+/////////////////////////
+// toReferences
+/////////////////////////
+template<template<typename...> class ResultContainer, typename SourceContainer>
+auto toReferences(SourceContainer &sources);
+template<typename SourceContainer>
+auto toReferences(SourceContainer &sources);
+
+/////////////////////////
+// toConstReferences
+/////////////////////////
+template<template<typename...> class ResultContainer, typename SourceContainer>
+auto toConstReferences(const SourceContainer &sources);
+template<typename SourceContainer>
+auto toConstReferences(const SourceContainer &sources);
+
+/////////////////////////
+// take
+/////////////////////////
+template<class C, typename P>
+Q_REQUIRED_RESULT std::optional<typename C::value_type> take(C &container, P predicate);
+template<typename C, typename R, typename S>
+Q_REQUIRED_RESULT decltype(auto) take(C &container, R S::*member);
+template<typename C, typename R, typename S>
+Q_REQUIRED_RESULT decltype(auto) take(C &container, R (S::*function)() const);
+
+/////////////////////////
+// setUnionMerge
+/////////////////////////
+// Works like std::set_union but provides a merge function for items that match
+// !(a > b) && !(b > a) which normally means that there is an "equal" match.
+// It uses iterators to support move_iterators.
+template<class InputIt1, class InputIt2, class OutputIt, class Merge, class Compare>
+OutputIt setUnionMerge(InputIt1 first1,
+ InputIt1 last1,
+ InputIt2 first2,
+ InputIt2 last2,
+ OutputIt d_first,
+ Merge merge,
+ Compare comp);
+template<class InputIt1, class InputIt2, class OutputIt, class Merge>
+OutputIt setUnionMerge(
+ InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first, Merge merge);
+template<class OutputContainer, class InputContainer1, class InputContainer2, class Merge, class Compare>
+OutputContainer setUnionMerge(InputContainer1 &&input1,
+ InputContainer2 &&input2,
+ Merge merge,
+ Compare comp);
+template<class OutputContainer, class InputContainer1, class InputContainer2, class Merge>
+OutputContainer setUnionMerge(InputContainer1 &&input1, InputContainer2 &&input2, Merge merge);
+
+/////////////////////////
+// setUnion
+/////////////////////////
+template<typename InputIterator1, typename InputIterator2, typename OutputIterator, typename Compare>
+OutputIterator set_union(InputIterator1 first1,
+ InputIterator1 last1,
+ InputIterator2 first2,
+ InputIterator2 last2,
+ OutputIterator result,
+ Compare comp);
+template<typename InputIterator1, typename InputIterator2, typename OutputIterator>
+OutputIterator set_union(InputIterator1 first1,
+ InputIterator1 last1,
+ InputIterator2 first2,
+ InputIterator2 last2,
+ OutputIterator result);
+
+/////////////////////////
+// transform
+/////////////////////////
+// function without result type deduction:
+template<typename ResultContainer, // complete result container type
+ typename SC, // input container type
+ typename F> // function type
+Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, F function);
+
+// function with result type deduction:
+template<template<typename> class C, // result container type
+ typename SC, // input container type
+ typename F, // function type
+ typename Value = typename std::decay_t<SC>::value_type,
+ typename Result = std::decay_t<std::result_of_t<F(Value &)>>,
+ typename ResultContainer = C<Result>>
+Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, F function);
+#ifdef Q_CC_CLANG
+// "Matching of template template-arguments excludes compatible templates"
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0522r0.html (P0522R0)
+// in C++17 makes the above match e.g. C=std::vector even though that takes two
+// template parameters. Unfortunately the following one matches too, and there is no additional
+// partial ordering rule, resulting in an ambiguous call for this previously valid code.
+// GCC and MSVC ignore that issue and follow the standard to the letter, but Clang only
+// enables the new behavior when given -frelaxed-template-template-args .
+// To avoid requiring everyone using this header to enable that feature, keep the old implementation
+// for Clang.
+template<template<typename, typename> class C, // result container type
+ typename SC, // input container type
+ typename F, // function type
+ typename Value = typename std::decay_t<SC>::value_type,
+ typename Result = std::decay_t<std::result_of_t<F(Value &)>>,
+ typename ResultContainer = C<Result, std::allocator<Result>>>
+Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, F function);
+#endif
+
+// member function without result type deduction:
+template<template<typename...> class C, // result container type
+ typename SC, // input container type
+ typename R,
+ typename S>
+Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, R (S::*p)() const);
+
+// member function with result type deduction:
+template<typename ResultContainer, // complete result container type
+ typename SC, // input container type
+ typename R,
+ typename S>
+Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, R (S::*p)() const);
+
+// member without result type deduction:
+template<typename ResultContainer, // complete result container type
+ typename SC, // input container
+ typename R,
+ typename S>
+Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, R S::*p);
+
+// member with result type deduction:
+template<template<typename...> class C, // result container
+ typename SC, // input container
+ typename R,
+ typename S>
+Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, R S::*p);
+
+// same container types for input and output, const input
+// function:
+template<template<typename...> class C, // container type
+ typename F, // function type
+ typename... CArgs> // Arguments to SC
+Q_REQUIRED_RESULT decltype(auto) transform(const C<CArgs...> &container, F function);
+
+// same container types for input and output, const input
+// member function:
+template<template<typename...> class C, // container type
+ typename R,
+ typename S,
+ typename... CArgs> // Arguments to SC
+Q_REQUIRED_RESULT decltype(auto) transform(const C<CArgs...> &container, R (S::*p)() const);
+
+// same container types for input and output, const input
+// members:
+template<template<typename...> class C, // container
+ typename R,
+ typename S,
+ typename... CArgs> // Arguments to SC
+Q_REQUIRED_RESULT decltype(auto) transform(const C<CArgs...> &container, R S::*p);
+
+// same container types for input and output, non-const input
+// function:
+template<template<typename...> class C, // container type
+ typename F, // function type
+ typename... CArgs> // Arguments to SC
+Q_REQUIRED_RESULT decltype(auto) transform(C<CArgs...> &container, F function);
+
+// same container types for input and output, non-const input
+// member function:
+template<template<typename...> class C, // container type
+ typename R,
+ typename S,
+ typename... CArgs> // Arguments to SC
+Q_REQUIRED_RESULT decltype(auto) transform(C<CArgs...> &container, R (S::*p)() const);
+
+// same container types for input and output, non-const input
+// members:
+template<template<typename...> class C, // container
+ typename R,
+ typename S,
+ typename... CArgs> // Arguments to SC
+Q_REQUIRED_RESULT decltype(auto) transform(C<CArgs...> &container, R S::*p);
+
+/////////////////////////////////////////////////////////////////////////////
+//////// Implementations //////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+//////////////////
+// anyOf
+/////////////////
+template<typename T, typename F>
+bool anyOf(const T &container, F predicate)
+{
+ return std::any_of(std::begin(container), std::end(container), predicate);
+}
+
+// anyOf taking a member function pointer
+template<typename T, typename R, typename S>
+bool anyOf(const T &container, R (S::*predicate)() const)
+{
+ return std::any_of(std::begin(container), std::end(container), std::mem_fn(predicate));
+}
+
+// anyOf taking a member pointer
+template<typename T, typename R, typename S>
+bool anyOf(const T &container, R S::*member)
+{
+ return std::any_of(std::begin(container), std::end(container), std::mem_fn(member));
+}
+
+
+//////////////////
+// count
+/////////////////
+template<typename T, typename F>
+int count(const T &container, F predicate)
+{
+ return std::count_if(std::begin(container), std::end(container), predicate);
+}
+
+//////////////////
+// allOf
+/////////////////
+template<typename T, typename F>
+bool allOf(const T &container, F predicate)
+{
+ return std::all_of(std::begin(container), std::end(container), predicate);
+}
+
+// allOf taking a member function pointer
+template<typename T, typename R, typename S>
+bool allOf(const T &container, R (S::*predicate)() const)
+{
+ return std::all_of(std::begin(container), std::end(container), std::mem_fn(predicate));
+}
+
+// allOf taking a member pointer
+template<typename T, typename R, typename S>
+bool allOf(const T &container, R S::*member)
+{
+ return std::all_of(std::begin(container), std::end(container), std::mem_fn(member));
+}
+
+//////////////////
+// erase
+/////////////////
+template<typename T, typename F>
+void erase(T &container, F predicate)
+{
+ container.erase(std::remove_if(std::begin(container), std::end(container), predicate),
+ std::end(container));
+}
+template<typename T, typename F>
+bool eraseOne(T &container, F predicate)
+{
+ const auto it = std::find_if(std::begin(container), std::end(container), predicate);
+ if (it == std::end(container))
+ return false;
+ container.erase(it);
+ return true;
+}
+
+//////////////////
+// contains
+/////////////////
+template<typename T, typename F>
+bool contains(const T &container, F function)
+{
+ return anyOf(container, function);
+}
+
+template<typename T, typename R, typename S>
+bool contains(const T &container, R (S::*function)() const)
+{
+ return anyOf(container, function);
+}
+
+template<typename C, typename R, typename S>
+bool contains(const C &container, R S::*member)
+{
+ return anyOf(container, std::mem_fn(member));
+}
+
+//////////////////
+// findOr
+/////////////////
+template<typename C, typename F>
+Q_REQUIRED_RESULT
+typename C::value_type findOr(const C &container, typename C::value_type other, F function)
+{
+ typename C::const_iterator begin = std::begin(container);
+ typename C::const_iterator end = std::end(container);
+
+ typename C::const_iterator it = std::find_if(begin, end, function);
+ return it == end ? other : *it;
+}
+
+template<typename T, typename R, typename S>
+Q_REQUIRED_RESULT
+typename T::value_type findOr(const T &container, typename T::value_type other, R (S::*function)() const)
+{
+ return findOr(container, other, std::mem_fn(function));
+}
+
+template<typename T, typename R, typename S>
+Q_REQUIRED_RESULT
+typename T::value_type findOr(const T &container, typename T::value_type other, R S::*member)
+{
+ return findOr(container, other, std::mem_fn(member));
+}
+
+//////////////////
+// findOrDefault
+//////////////////
+// Default implementation:
+template<typename C, typename F>
+Q_REQUIRED_RESULT
+typename std::enable_if_t<std::is_copy_assignable<typename C::value_type>::value, typename C::value_type>
+findOrDefault(const C &container, F function)
+{
+ return findOr(container, typename C::value_type(), function);
+}
+
+template<typename C, typename R, typename S>
+Q_REQUIRED_RESULT
+typename std::enable_if_t<std::is_copy_assignable<typename C::value_type>::value, typename C::value_type>
+findOrDefault(const C &container, R (S::*function)() const)
+{
+ return findOr(container, typename C::value_type(), std::mem_fn(function));
+}
+
+template<typename C, typename R, typename S>
+Q_REQUIRED_RESULT
+typename std::enable_if_t<std::is_copy_assignable<typename C::value_type>::value, typename C::value_type>
+findOrDefault(const C &container, R S::*member)
+{
+ return findOr(container, typename C::value_type(), std::mem_fn(member));
+}
+
+//////////////////
+// index of:
+//////////////////
+
+template<typename C, typename F>
+Q_REQUIRED_RESULT
+int indexOf(const C& container, F function)
+{
+ typename C::const_iterator begin = std::begin(container);
+ typename C::const_iterator end = std::end(container);
+
+ typename C::const_iterator it = std::find_if(begin, end, function);
+ return it == end ? -1 : std::distance(begin, it);
+}
+
+
+//////////////////
+// max element
+//////////////////
+
+template<typename T>
+typename T::value_type maxElementOr(const T &container, typename T::value_type other)
+{
+ typename T::const_iterator begin = std::begin(container);
+ typename T::const_iterator end = std::end(container);
+
+ typename T::const_iterator it = std::max_element(begin, end);
+ if (it == end)
+ return other;
+ return *it;
+}
+
+
+//////////////////
+// transform
+/////////////////
+
+namespace {
+/////////////////
+// helper code for transform to use back_inserter and thus push_back for everything
+// and insert for QSet<>
+//
+
+// SetInsertIterator, straight from the standard for insert_iterator
+// just without the additional parameter to insert
+template<class Container>
+class SetInsertIterator
+{
+protected:
+ Container *container;
+
+public:
+ using iterator_category = std::output_iterator_tag;
+ using container_type = Container;
+ explicit SetInsertIterator(Container &x)
+ : container(&x)
+ {}
+ SetInsertIterator<Container> &operator=(const typename Container::value_type &value)
+ {
+ container->insert(value);
+ return *this;
+ }
+ SetInsertIterator<Container> &operator=(typename Container::value_type &&value)
+ {
+ container->insert(std::move(value));
+ return *this;
+ }
+ SetInsertIterator<Container> &operator*() { return *this; }
+ SetInsertIterator<Container> &operator++() { return *this; }
+ SetInsertIterator<Container> operator++(int) { return *this; }
+};
+
+// for QMap / QHash, inserting a std::pair / QPair
+template<class Container>
+class MapInsertIterator
+{
+protected:
+ Container *container;
+
+public:
+ using iterator_category = std::output_iterator_tag;
+ using container_type = Container;
+ explicit MapInsertIterator(Container &x)
+ : container(&x)
+ {}
+ MapInsertIterator<Container> &operator=(
+ const std::pair<const typename Container::key_type, typename Container::mapped_type> &value)
+ { container->insert(value.first, value.second); return *this; }
+ MapInsertIterator<Container> &operator=(
+ const QPair<typename Container::key_type, typename Container::mapped_type> &value)
+ { container->insert(value.first, value.second); return *this; }
+ MapInsertIterator<Container> &operator*() { return *this; }
+ MapInsertIterator<Container> &operator++() { return *this; }
+ MapInsertIterator<Container> operator++(int) { return *this; }
+};
+
+// because Qt container are not implementing the standard interface we need
+// this helper functions for generic code
+template<typename Type>
+void append(QList<Type> *container, QList<Type> &&input)
+{
+ container->append(std::move(input));
+}
+
+template<typename Type>
+void append(QList<Type> *container, const QList<Type> &input)
+{
+ container->append(input);
+}
+
+template<typename Container>
+void append(Container *container, Container &&input)
+{
+ container->insert(container->end(),
+ std::make_move_iterator(input.begin()),
+ std::make_move_iterator(input.end()));
+}
+
+template<typename Container>
+void append(Container *container, const Container &input)
+{
+ container->insert(container->end(), input.begin(), input.end());
+}
+
+// BackInsertIterator behaves like std::back_insert_iterator except is adds the back insertion for
+// container of the same type
+template<typename Container>
+class BackInsertIterator
+{
+public:
+ using iterator_category = std::output_iterator_tag;
+ using value_type = void;
+ using difference_type = ptrdiff_t;
+ using pointer = void;
+ using reference = void;
+ using container_type = Container;
+
+ explicit constexpr BackInsertIterator(Container &container)
+ : m_container(std::addressof(container))
+ {}
+
+ constexpr BackInsertIterator &operator=(const typename Container::value_type &value)
+ {
+ m_container->push_back(value);
+ return *this;
+ }
+
+ constexpr BackInsertIterator &operator=(typename Container::value_type &&value)
+ {
+ m_container->push_back(std::move(value));
+ return *this;
+ }
+
+ constexpr BackInsertIterator &operator=(const Container &container)
+ {
+ append(m_container, container);
+ return *this;
+ }
+
+ constexpr BackInsertIterator &operator=(Container &&container)
+ {
+ append(m_container, container);
+ return *this;
+ }
+
+ [[nodiscard]] constexpr BackInsertIterator &operator*() { return *this; }
+
+ constexpr BackInsertIterator &operator++() { return *this; }
+
+ constexpr BackInsertIterator operator++(int) { return *this; }
+
+private:
+ Container *m_container;
+};
+
+// inserter helper function, returns a BackInsertIterator for most containers
+// and is overloaded for QSet<> and other containers without push_back, returning custom inserters
+template<typename Container>
+inline BackInsertIterator<Container> inserter(Container &container)
+{
+ return BackInsertIterator(container);
+}
+
+template<typename X>
+inline SetInsertIterator<QSet<X>>
+inserter(QSet<X> &container)
+{
+ return SetInsertIterator<QSet<X>>(container);
+}
+
+template<typename K, typename C, typename A>
+inline SetInsertIterator<std::set<K, C, A>>
+inserter(std::set<K, C, A> &container)
+{
+ return SetInsertIterator<std::set<K, C, A>>(container);
+}
+
+template<typename K, typename H, typename C, typename A>
+inline SetInsertIterator<std::unordered_set<K, H, C, A>>
+inserter(std::unordered_set<K, H, C, A> &container)
+{
+ return SetInsertIterator<std::unordered_set<K, H, C, A>>(container);
+}
+
+template<typename K, typename V, typename C, typename A>
+inline SetInsertIterator<std::map<K, V, C, A>>
+inserter(std::map<K, V, C, A> &container)
+{
+ return SetInsertIterator<std::map<K, V, C, A>>(container);
+}
+
+template<typename K, typename V, typename H, typename C, typename A>
+inline SetInsertIterator<std::unordered_map<K, V, H, C, A>>
+inserter(std::unordered_map<K, V, H, C, A> &container)
+{
+ return SetInsertIterator<std::unordered_map<K, V, H, C, A>>(container);
+}
+
+template<typename K, typename V>
+inline MapInsertIterator<QMap<K, V>>
+inserter(QMap<K, V> &container)
+{
+ return MapInsertIterator<QMap<K, V>>(container);
+}
+
+template<typename K, typename V>
+inline MapInsertIterator<QHash<K, V>>
+inserter(QHash<K, V> &container)
+{
+ return MapInsertIterator<QHash<K, V>>(container);
+}
+
+// Helper code for container.reserve that makes it possible to effectively disable it for
+// specific cases
+
+// default: do reserve
+// Template arguments are more specific than the second version below, so this is tried first
+template<template<typename...> class C, typename... CArgs,
+ typename = decltype(&C<CArgs...>::reserve)>
+void reserve(C<CArgs...> &c, typename C<CArgs...>::size_type s)
+{
+ c.reserve(s);
+}
+
+// containers that don't have reserve()
+template<typename C>
+void reserve(C &, typename C::size_type) { }
+
+} // anonymous
+
+// --------------------------------------------------------------------
+// Different containers for input and output:
+// --------------------------------------------------------------------
+
+// different container types for input and output, e.g. transforming a QList into a QSet
+
+// function without result type deduction:
+template<typename ResultContainer, // complete result container type
+ typename SC, // input container type
+ typename F> // function type
+Q_REQUIRED_RESULT
+decltype(auto) transform(SC &&container, F function)
+{
+ ResultContainer result;
+ reserve(result, typename ResultContainer::size_type(container.size()));
+ std::transform(std::begin(container), std::end(container), inserter(result), function);
+ return result;
+}
+
+// function with result type deduction:
+template<template<typename> class C, // result container type
+ typename SC, // input container type
+ typename F, // function type
+ typename Value,
+ typename Result,
+ typename ResultContainer>
+Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, F function)
+{
+ return transform<ResultContainer>(std::forward<SC>(container), function);
+}
+
+#ifdef Q_CC_CLANG
+template<template<typename, typename> class C, // result container type
+ typename SC, // input container type
+ typename F, // function type
+ typename Value,
+ typename Result,
+ typename ResultContainer>
+Q_REQUIRED_RESULT decltype(auto) transform(SC &&container, F function)
+{
+ return transform<ResultContainer>(std::forward<SC>(container), function);
+}
+#endif
+
+// member function without result type deduction:
+template<template<typename...> class C, // result container type
+ typename SC, // input container type
+ typename R,
+ typename S>
+Q_REQUIRED_RESULT
+decltype(auto) transform(SC &&container, R (S::*p)() const)
+{
+ return transform<C>(std::forward<SC>(container), std::mem_fn(p));
+}
+
+// member function with result type deduction:
+template<typename ResultContainer, // complete result container type
+ typename SC, // input container type
+ typename R,
+ typename S>
+Q_REQUIRED_RESULT
+decltype(auto) transform(SC &&container, R (S::*p)() const)
+{
+ return transform<ResultContainer>(std::forward<SC>(container), std::mem_fn(p));
+}
+
+// member without result type deduction:
+template<typename ResultContainer, // complete result container type
+ typename SC, // input container
+ typename R,
+ typename S>
+Q_REQUIRED_RESULT
+decltype(auto) transform(SC &&container, R S::*p)
+{
+ return transform<ResultContainer>(std::forward<SC>(container), std::mem_fn(p));
+}
+
+// member with result type deduction:
+template<template<typename...> class C, // result container
+ typename SC, // input container
+ typename R,
+ typename S>
+Q_REQUIRED_RESULT
+decltype(auto) transform(SC &&container, R S::*p)
+{
+ return transform<C>(std::forward<SC>(container), std::mem_fn(p));
+}
+
+// same container types for input and output, const input
+
+// function:
+template<template<typename...> class C, // container type
+ typename F, // function type
+ typename... CArgs> // Arguments to SC
+Q_REQUIRED_RESULT
+decltype(auto) transform(const C<CArgs...> &container, F function)
+{
+ return transform<C, const C<CArgs...> &>(container, function);
+}
+
+// member function:
+template<template<typename...> class C, // container type
+ typename R,
+ typename S,
+ typename... CArgs> // Arguments to SC
+Q_REQUIRED_RESULT
+decltype(auto) transform(const C<CArgs...> &container, R (S::*p)() const)
+{
+ return transform<C, const C<CArgs...> &>(container, std::mem_fn(p));
+}
+
+// members:
+template<template<typename...> class C, // container
+ typename R,
+ typename S,
+ typename... CArgs> // Arguments to SC
+Q_REQUIRED_RESULT
+decltype(auto) transform(const C<CArgs...> &container, R S::*p)
+{
+ return transform<C, const C<CArgs...> &>(container, std::mem_fn(p));
+}
+
+// same container types for input and output, non-const input
+
+// function:
+template<template<typename...> class C, // container type
+ typename F, // function type
+ typename... CArgs> // Arguments to SC
+Q_REQUIRED_RESULT
+decltype(auto) transform(C<CArgs...> &container, F function)
+{
+ return transform<C, C<CArgs...> &>(container, function);
+}
+
+// member function:
+template<template<typename...> class C, // container type
+ typename R,
+ typename S,
+ typename... CArgs> // Arguments to SC
+Q_REQUIRED_RESULT
+decltype(auto) transform(C<CArgs...> &container, R (S::*p)() const)
+{
+ return transform<C, C<CArgs...> &>(container, std::mem_fn(p));
+}
+
+// members:
+template<template<typename...> class C, // container
+ typename R,
+ typename S,
+ typename... CArgs> // Arguments to SC
+Q_REQUIRED_RESULT
+decltype(auto) transform(C<CArgs...> &container, R S::*p)
+{
+ return transform<C, C<CArgs...> &>(container, std::mem_fn(p));
+}
+
+// Specialization for QStringList:
+
+template<template<typename...> class C = QList, // result container
+ typename F> // Arguments to C
+Q_REQUIRED_RESULT
+decltype(auto) transform(const QStringList &container, F function)
+{
+ return transform<C, const QList<QString> &>(static_cast<QList<QString>>(container), function);
+}
+
+// member function:
+template<template<typename...> class C = QList, // result container type
+ typename R,
+ typename S>
+Q_REQUIRED_RESULT
+decltype(auto) transform(const QStringList &container, R (S::*p)() const)
+{
+ return transform<C, const QList<QString> &>(static_cast<QList<QString>>(container), std::mem_fn(p));
+}
+
+// members:
+template<template<typename...> class C = QList, // result container
+ typename R,
+ typename S>
+Q_REQUIRED_RESULT
+decltype(auto) transform(const QStringList &container, R S::*p)
+{
+ return transform<C, const QList<QString> &>(static_cast<QList<QString>>(container), std::mem_fn(p));
+}
+
+//////////////////
+// filtered
+/////////////////
+template<typename C, typename F>
+Q_REQUIRED_RESULT
+C filtered(const C &container, F predicate)
+{
+ C out;
+ std::copy_if(std::begin(container), std::end(container),
+ inserter(out), predicate);
+ return out;
+}
+
+template<typename C, typename R, typename S>
+Q_REQUIRED_RESULT
+C filtered(const C &container, R (S::*predicate)() const)
+{
+ C out;
+ std::copy_if(std::begin(container), std::end(container),
+ inserter(out), std::mem_fn(predicate));
+ return out;
+}
+
+//////////////////
+// filteredCast
+/////////////////
+template<typename R, typename C, typename F>
+Q_REQUIRED_RESULT R filteredCast(const C &container, F predicate)
+{
+ R out;
+ std::copy_if(std::begin(container), std::end(container), inserter(out), predicate);
+ return out;
+}
+
+//////////////////
+// partition
+/////////////////
+
+// Recommended usage:
+// C hit;
+// C miss;
+// std::tie(hit, miss) = Utils::partition(container, predicate);
+
+template<typename C, typename F>
+Q_REQUIRED_RESULT
+std::tuple<C, C> partition(const C &container, F predicate)
+{
+ C hit;
+ C miss;
+ reserve(hit, container.size());
+ reserve(miss, container.size());
+ auto hitIns = inserter(hit);
+ auto missIns = inserter(miss);
+ for (const auto &i : container) {
+ if (predicate(i))
+ hitIns = i;
+ else
+ missIns = i;
+ }
+ return std::make_tuple(hit, miss);
+}
+
+template<typename C, typename R, typename S>
+Q_REQUIRED_RESULT
+std::tuple<C, C> partition(const C &container, R (S::*predicate)() const)
+{
+ return partition(container, std::mem_fn(predicate));
+}
+
+//////////////////
+// filteredUnique
+/////////////////
+
+template<typename C>
+Q_REQUIRED_RESULT
+C filteredUnique(const C &container)
+{
+ C result;
+ auto ins = inserter(result);
+
+ QSet<typename C::value_type> seen;
+ int setSize = 0;
+
+ auto endIt = std::end(container);
+ for (auto it = std::begin(container); it != endIt; ++it) {
+ seen.insert(*it);
+ if (setSize == seen.size()) // unchanged size => was already seen
+ continue;
+ ++setSize;
+ ins = *it;
+ }
+ return result;
+}
+
+//////////////////
+// qobject_container_cast
+/////////////////
+template <class T, template<typename> class Container, typename Base>
+Container<T> qobject_container_cast(const Container<Base> &container)
+{
+ Container<T> result;
+ auto ins = inserter(result);
+ for (Base val : container) {
+ if (T target = qobject_cast<T>(val))
+ ins = target;
+ }
+ return result;
+}
+
+//////////////////
+// static_container_cast
+/////////////////
+template <class T, template<typename> class Container, typename Base>
+Container<T> static_container_cast(const Container<Base> &container)
+{
+ Container<T> result;
+ reserve(result, container.size());
+ auto ins = inserter(result);
+ for (Base val : container)
+ ins = static_cast<T>(val);
+ return result;
+}
+
+//////////////////
+// sort
+/////////////////
+template <typename Container>
+inline void sort(Container &container)
+{
+ std::stable_sort(std::begin(container), std::end(container));
+}
+
+template <typename Container, typename Predicate>
+inline void sort(Container &container, Predicate p)
+{
+ std::stable_sort(std::begin(container), std::end(container), p);
+}
+
+// const lvalue
+template<typename Container>
+inline Container sorted(const Container &container)
+{
+ Container c = container;
+ sort(c);
+ return c;
+}
+
+// non-const lvalue
+// This is needed because otherwise the "universal" reference below is used, modifying the input
+// container.
+template<typename Container>
+inline Container sorted(Container &container)
+{
+ Container c = container;
+ sort(c);
+ return c;
+}
+
+// non-const rvalue (actually rvalue or lvalue, but lvalue is handled above)
+template<typename Container>
+inline Container sorted(Container &&container)
+{
+ sort(container);
+ return std::move(container);
+}
+
+// const rvalue
+template<typename Container>
+inline Container sorted(const Container &&container)
+{
+ return sorted(container);
+}
+
+// const lvalue
+template<typename Container, typename Predicate>
+inline Container sorted(const Container &container, Predicate p)
+{
+ Container c = container;
+ sort(c, p);
+ return c;
+}
+
+// non-const lvalue
+// This is needed because otherwise the "universal" reference below is used, modifying the input
+// container.
+template<typename Container, typename Predicate>
+inline Container sorted(Container &container, Predicate p)
+{
+ Container c = container;
+ sort(c, p);
+ return c;
+}
+
+// non-const rvalue (actually rvalue or lvalue, but lvalue is handled above)
+template<typename Container, typename Predicate>
+inline Container sorted(Container &&container, Predicate p)
+{
+ sort(container, p);
+ return std::move(container);
+}
+
+// const rvalue
+template<typename Container, typename Predicate>
+inline Container sorted(const Container &&container, Predicate p)
+{
+ return sorted(container, p);
+}
+
+// pointer to member
+template<typename Container, typename R, typename S>
+inline void sort(Container &container, R S::*member)
+{
+ auto f = std::mem_fn(member);
+ using const_ref = typename Container::const_reference;
+ std::stable_sort(std::begin(container), std::end(container),
+ [&f](const_ref a, const_ref b) {
+ return f(a) < f(b);
+ });
+}
+
+// const lvalue
+template<typename Container, typename R, typename S>
+inline Container sorted(const Container &container, R S::*member)
+{
+ Container c = container;
+ sort(c, member);
+ return c;
+}
+
+// non-const lvalue
+// This is needed because otherwise the "universal" reference below is used, modifying the input
+// container.
+template<typename Container, typename R, typename S>
+inline Container sorted(Container &container, R S::*member)
+{
+ Container c = container;
+ sort(c, member);
+ return c;
+}
+
+// non-const rvalue (actually rvalue or lvalue, but lvalue is handled above)
+template<typename Container, typename R, typename S>
+inline Container sorted(Container &&container, R S::*member)
+{
+ sort(container, member);
+ return std::move(container);
+}
+
+// const rvalue
+template<typename Container, typename R, typename S>
+inline Container sorted(const Container &&container, R S::*member)
+{
+ return sorted(container, member);
+}
+
+// pointer to member function
+template<typename Container, typename R, typename S>
+inline void sort(Container &container, R (S::*function)() const)
+{
+ auto f = std::mem_fn(function);
+ using const_ref = typename Container::const_reference;
+ std::stable_sort(std::begin(container), std::end(container),
+ [&f](const_ref a, const_ref b) {
+ return f(a) < f(b);
+ });
+}
+
+// const lvalue
+template<typename Container, typename R, typename S>
+inline Container sorted(const Container &container, R (S::*function)() const)
+{
+ Container c = container;
+ sort(c, function);
+ return c;
+}
+
+// non-const lvalue
+// This is needed because otherwise the "universal" reference below is used, modifying the input
+// container.
+template<typename Container, typename R, typename S>
+inline Container sorted(Container &container, R (S::*function)() const)
+{
+ Container c = container;
+ sort(c, function);
+ return c;
+}
+
+// non-const rvalue (actually rvalue or lvalue, but lvalue is handled above)
+template<typename Container, typename R, typename S>
+inline Container sorted(Container &&container, R (S::*function)() const)
+{
+ sort(container, function);
+ return std::move(container);
+}
+
+// const rvalue
+template<typename Container, typename R, typename S>
+inline Container sorted(const Container &&container, R (S::*function)() const)
+{
+ return sorted(container, function);
+}
+
+//////////////////
+// reverseForeach
+/////////////////
+template <typename Container, typename Op>
+inline void reverseForeach(const Container &c, const Op &operation)
+{
+ auto rend = c.rend();
+ for (auto it = c.rbegin(); it != rend; ++it)
+ operation(*it);
+}
+
+//////////////////
+// toReferences
+/////////////////
+template <template<typename...> class ResultContainer,
+ typename SourceContainer>
+auto toReferences(SourceContainer &sources)
+{
+ return transform<ResultContainer>(sources, [] (auto &value) { return std::ref(value); });
+}
+
+template <typename SourceContainer>
+auto toReferences(SourceContainer &sources)
+{
+ return transform(sources, [] (auto &value) { return std::ref(value); });
+}
+
+//////////////////
+// toConstReferences
+/////////////////
+template <template<typename...> class ResultContainer,
+ typename SourceContainer>
+auto toConstReferences(const SourceContainer &sources)
+{
+ return transform<ResultContainer>(sources, [] (const auto &value) { return std::cref(value); });
+}
+
+template <typename SourceContainer>
+auto toConstReferences(const SourceContainer &sources)
+{
+ return transform(sources, [] (const auto &value) { return std::cref(value); });
+}
+
+//////////////////
+// take:
+/////////////////
+
+template<class C, typename P>
+Q_REQUIRED_RESULT std::optional<typename C::value_type> take(C &container, P predicate)
+{
+ const auto end = std::end(container);
+
+ const auto it = std::find_if(std::begin(container), end, predicate);
+ if (it == end)
+ return std::nullopt;
+
+ std::optional<typename C::value_type> result = std::make_optional(std::move(*it));
+ container.erase(it);
+ return result;
+}
+
+// pointer to member
+template <typename C, typename R, typename S>
+Q_REQUIRED_RESULT decltype(auto) take(C &container, R S::*member)
+{
+ return take(container, std::mem_fn(member));
+}
+
+// pointer to member function
+template <typename C, typename R, typename S>
+Q_REQUIRED_RESULT decltype(auto) take(C &container, R (S::*function)() const)
+{
+ return take(container, std::mem_fn(function));
+}
+
+//////////////////
+// setUnionMerge: Works like std::set_union but provides a merge function for items that match
+// !(a > b) && !(b > a) which normally means that there is an "equal" match.
+// It uses iterators to support move_iterators.
+/////////////////
+
+template<class InputIt1,
+ class InputIt2,
+ class OutputIt,
+ class Merge,
+ class Compare>
+OutputIt setUnionMerge(InputIt1 first1,
+ InputIt1 last1,
+ InputIt2 first2,
+ InputIt2 last2,
+ OutputIt d_first,
+ Merge merge,
+ Compare comp)
+{
+ for (; first1 != last1; ++d_first) {
+ if (first2 == last2)
+ return std::copy(first1, last1, d_first);
+ if (comp(*first2, *first1)) {
+ *d_first = *first2++;
+ } else {
+ if (comp(*first1, *first2)) {
+ *d_first = *first1;
+ } else {
+ *d_first = merge(*first1, *first2);
+ ++first2;
+ }
+ ++first1;
+ }
+ }
+ return std::copy(first2, last2, d_first);
+}
+
+template<class InputIt1,
+ class InputIt2,
+ class OutputIt,
+ class Merge>
+OutputIt setUnionMerge(InputIt1 first1,
+ InputIt1 last1,
+ InputIt2 first2,
+ InputIt2 last2,
+ OutputIt d_first,
+ Merge merge)
+{
+ return setUnionMerge(first1,
+ last1,
+ first2,
+ last2,
+ d_first,
+ merge,
+ std::less<std::decay_t<decltype(*first1)>>{});
+}
+
+template<class OutputContainer,
+ class InputContainer1,
+ class InputContainer2,
+ class Merge,
+ class Compare>
+OutputContainer setUnionMerge(InputContainer1 &&input1,
+ InputContainer2 &&input2,
+ Merge merge,
+ Compare comp)
+{
+ OutputContainer results;
+ results.reserve(input1.size() + input2.size());
+
+ setUnionMerge(std::make_move_iterator(std::begin(input1)),
+ std::make_move_iterator(std::end(input1)),
+ std::make_move_iterator(std::begin(input2)),
+ std::make_move_iterator(std::end(input2)),
+ std::back_inserter(results),
+ merge,
+ comp);
+
+ return results;
+}
+
+template<class OutputContainer,
+ class InputContainer1,
+ class InputContainer2,
+ class Merge>
+OutputContainer setUnionMerge(InputContainer1 &&input1,
+ InputContainer2 &&input2,
+ Merge merge)
+{
+ return setUnionMerge<OutputContainer>(std::forward<InputContainer1>(input1),
+ std::forward<InputContainer2>(input2),
+ merge,
+ std::less<std::decay_t<decltype(*std::begin(input1))>>{});
+}
+
+template<typename Container>
+auto usize(const Container &container)
+{
+ return static_cast<std::make_unsigned_t<decltype(std::size(container))>>(std::size(container));
+}
+
+template<typename Container>
+auto ssize(const Container &container)
+{
+ return static_cast<std::make_signed_t<decltype(std::size(container))>>(std::size(container));
+}
+
+template<typename Compare>
+struct CompareIter
+{
+ Compare compare;
+
+ explicit constexpr CompareIter(Compare compare)
+ : compare(std::move(compare))
+ {}
+
+ template<typename Iterator1, typename Iterator2>
+ constexpr bool operator()(Iterator1 it1, Iterator2 it2)
+ {
+ return bool(compare(*it1, *it2));
+ }
+};
+
+template<typename InputIterator1, typename InputIterator2, typename OutputIterator, typename Compare>
+OutputIterator set_union_impl(InputIterator1 first1,
+ InputIterator1 last1,
+ InputIterator2 first2,
+ InputIterator2 last2,
+ OutputIterator result,
+ Compare comp)
+{
+ auto compare = CompareIter<Compare>(comp);
+
+ while (first1 != last1 && first2 != last2) {
+ if (compare(first1, first2)) {
+ *result = *first1;
+ ++first1;
+ } else if (compare(first2, first1)) {
+ *result = *first2;
+ ++first2;
+ } else {
+ *result = *first1;
+ ++first1;
+ ++first2;
+ }
+ ++result;
+ }
+
+ return std::copy(first2, last2, std::copy(first1, last1, result));
+}
+
+template<typename InputIterator1, typename InputIterator2, typename OutputIterator, typename Compare>
+OutputIterator set_union(InputIterator1 first1,
+ InputIterator1 last1,
+ InputIterator2 first2,
+ InputIterator2 last2,
+ OutputIterator result,
+ Compare comp)
+{
+ return set_union_impl(first1, last1, first2, last2, result, comp);
+}
+
+template<typename InputIterator1, typename InputIterator2, typename OutputIterator>
+OutputIterator set_union(InputIterator1 first1,
+ InputIterator1 last1,
+ InputIterator2 first2,
+ InputIterator2 last2,
+ OutputIterator result)
+{
+ return set_union_impl(
+ first1, last1, first2, last2, result, std::less<typename InputIterator1::value_type>{});
+}
+
+// Replacement for deprecated Qt functionality
+
+template <class T>
+QSet<T> toSet(const QList<T> &list)
+{
+ return QSet<T>(list.begin(), list.end());
+}
+
+template<class T>
+QList<T> toList(const QSet<T> &set)
+{
+ return QList<T>(set.begin(), set.end());
+}
+
+template <class Key, class T>
+void addToHash(QHash<Key, T> *result, const QHash<Key, T> &additionalContents)
+{
+ result->insert(additionalContents);
+}
+
+// Workaround for missing information from QSet::insert()
+// Return type could be a pair like for std::set, but we never use the iterator anyway.
+template<typename T, typename U> [[nodiscard]] bool insert(QSet<T> &s, const U &v)
+{
+ const int oldSize = s.size();
+ s.insert(v);
+ return s.size() > oldSize;
+}
+
+} // namespace lsp::Utils
diff --git a/src/shared/lsp/basemessage.cpp b/src/shared/lsp/basemessage.cpp
new file mode 100644
index 000000000..4b19190dc
--- /dev/null
+++ b/src/shared/lsp/basemessage.cpp
@@ -0,0 +1,188 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "basemessage.h"
+
+#include "jsonrpcmessages.h"
+#include "languageserverprotocoltr.h"
+
+#include <QBuffer>
+#include <QTextCodec>
+
+#include <cstring>
+#include <utility>
+
+namespace lsp {
+
+Q_LOGGING_CATEGORY(parseLog, "qtc.languageserverprotocol.parse", QtWarningMsg)
+
+constexpr char headerFieldSeparator[] = ": ";
+constexpr char contentCharsetName[] = "charset";
+constexpr char defaultCharset[] = "utf-8";
+constexpr char contentLengthFieldName[] = "Content-Length";
+constexpr char headerSeparator[] = "\r\n";
+constexpr char contentTypeFieldName[] = "Content-Type";
+
+BaseMessage::BaseMessage()
+ : mimeType(JsonRpcMessage::jsonRpcMimeType())
+{ }
+
+BaseMessage::BaseMessage(const QByteArray &mimeType, const QByteArray &content,
+ int expectedLength, QTextCodec *codec)
+ : mimeType(mimeType.isEmpty() ? JsonRpcMessage::jsonRpcMimeType() : mimeType)
+ , content(content)
+ , contentLength(expectedLength)
+ , codec(codec)
+{ }
+
+BaseMessage::BaseMessage(const QByteArray &mimeType, const QByteArray &content)
+ : BaseMessage(mimeType, content, content.length(), defaultCodec())
+{ }
+
+bool BaseMessage::operator==(const BaseMessage &other) const
+{
+ if (mimeType != other.mimeType || content != other.content)
+ return false;
+ if (codec) {
+ if (other.codec)
+ return codec->mibEnum() == other.codec->mibEnum();
+ return codec->mibEnum() == defaultCodec()->mibEnum();
+ }
+ if (other.codec)
+ return other.codec->mibEnum() == defaultCodec()->mibEnum();
+
+ return true;
+}
+
+static QPair<QByteArray, QByteArray> splitHeaderFieldLine(const QByteArray &headerFieldLine)
+{
+ static const int fieldSeparatorLength = int(std::strlen(headerFieldSeparator));
+ int assignmentIndex = headerFieldLine.indexOf(headerFieldSeparator);
+ if (assignmentIndex >= 0) {
+ return {headerFieldLine.mid(0, assignmentIndex),
+ headerFieldLine.mid(assignmentIndex + fieldSeparatorLength)};
+ }
+ qCWarning(parseLog) << "Unexpected header line:" << QLatin1String(headerFieldLine);
+ return {};
+}
+
+static void parseContentType(BaseMessage &message, QByteArray contentType, QString &parseError)
+{
+ if (contentType.startsWith('"') && contentType.endsWith('"'))
+ contentType = contentType.mid(1, contentType.length() - 2);
+ QList<QByteArray> contentTypeElements = contentType.split(';');
+ QByteArray mimeTypeName = contentTypeElements.takeFirst();
+ QTextCodec *codec = nullptr;
+ for (const QByteArray &_contentTypeElement : contentTypeElements) {
+ const QByteArray &contentTypeElement = _contentTypeElement.trimmed();
+ if (contentTypeElement.startsWith(contentCharsetName)) {
+ const int equalindex = contentTypeElement.indexOf('=');
+ const QByteArray charset = contentTypeElement.mid(equalindex + 1);
+ if (equalindex > 0)
+ codec = QTextCodec::codecForName(charset);
+ if (!codec) {
+ parseError = Tr::tr("Cannot decode content with \"%1\". Falling back to \"%2\".")
+ .arg(QLatin1String(charset),
+ QLatin1String(defaultCharset));
+ }
+ }
+ }
+ message.mimeType = mimeTypeName;
+ message.codec = codec ? codec : BaseMessage::defaultCodec();
+}
+
+static void parseContentLength(BaseMessage &message, QByteArray contentLength, QString &parseError)
+{
+ bool ok = true;
+ message.contentLength = contentLength.toInt(&ok);
+ if (!ok) {
+ parseError = Tr::tr("Expected an integer in \"%1\", but got \"%2\".")
+ .arg(QString::fromLatin1(contentLengthFieldName), QString::fromLatin1(contentLength));
+ }
+}
+
+void BaseMessage::parse(QBuffer *data, QString &parseError, BaseMessage &message)
+{
+ const qint64 startPos = data->pos();
+
+ if (message.isValid()) { // incomplete message from last parse
+ message.content.append(data->read(message.contentLength - message.content.length()));
+ return;
+ }
+
+ while (!data->atEnd()) {
+ const QByteArray &headerFieldLine = data->readLine();
+ if (headerFieldLine == headerSeparator) {
+ if (message.isValid())
+ message.content = data->read(message.contentLength);
+ return;
+ }
+ const QPair<QByteArray, QByteArray> nameAndValue = splitHeaderFieldLine(headerFieldLine);
+ const QByteArray &headerFieldName = nameAndValue.first.trimmed();
+ const QByteArray &headerFieldValue = nameAndValue.second.trimmed();
+
+ if (headerFieldName.isEmpty())
+ continue;
+ if (headerFieldName == contentLengthFieldName) {
+ parseContentLength(message, headerFieldValue, parseError);
+ } else if (headerFieldName == contentTypeFieldName) {
+ parseContentType(message, headerFieldValue, parseError);
+ } else {
+ qCWarning(parseLog) << "Unexpected header field" << QLatin1String(headerFieldName)
+ << "in" << QLatin1String(headerFieldLine);
+ }
+ }
+
+ // the complete header wasn't received jet, waiting for the rest of it and reparse
+ message = BaseMessage();
+ data->seek(startPos);
+}
+
+QTextCodec *BaseMessage::defaultCodec()
+{
+ static QTextCodec *codec = QTextCodec::codecForName(defaultCharset);
+ return codec;
+}
+
+bool BaseMessage::isComplete() const
+{
+ if (!isValid())
+ return false;
+ QBS_ASSERT(content.length() <= contentLength, return true);
+ return content.length() == contentLength;
+}
+
+bool BaseMessage::isValid() const
+{
+ return contentLength >= 0;
+}
+
+QByteArray BaseMessage::header() const
+{
+ QByteArray header;
+ header.append(lengthHeader());
+ if (codec != defaultCodec()
+ || (!mimeType.isEmpty() && mimeType != JsonRpcMessage::jsonRpcMimeType())) {
+ header.append(typeHeader());
+ }
+ header.append(headerSeparator);
+ return header;
+}
+
+QByteArray BaseMessage::lengthHeader() const
+{
+ return QByteArray(contentLengthFieldName)
+ + QByteArray(headerFieldSeparator)
+ + QString::number(content.size()).toLatin1()
+ + QByteArray(headerSeparator);
+}
+
+QByteArray BaseMessage::typeHeader() const
+{
+ return QByteArray(contentTypeFieldName)
+ + QByteArray(headerFieldSeparator)
+ + mimeType + "; " + contentCharsetName + "=" + codec->name()
+ + QByteArray(headerSeparator);
+}
+
+} // namespace lsp
diff --git a/src/shared/lsp/basemessage.h b/src/shared/lsp/basemessage.h
new file mode 100644
index 000000000..4c6f0cb48
--- /dev/null
+++ b/src/shared/lsp/basemessage.h
@@ -0,0 +1,48 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "languageserverprotocol_global.h"
+
+#include <QByteArray>
+#include <QCoreApplication>
+#include <QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+class QBuffer;
+class QTextCodec;
+QT_END_NAMESPACE
+
+namespace lsp {
+
+LANGUAGESERVERPROTOCOL_EXPORT Q_DECLARE_LOGGING_CATEGORY(parseLog)
+
+class LANGUAGESERVERPROTOCOL_EXPORT BaseMessage
+{
+public:
+ BaseMessage();
+ BaseMessage(const QByteArray &mimeType, const QByteArray &content,
+ int expectedLength, QTextCodec *codec);
+ BaseMessage(const QByteArray &mimeType, const QByteArray &content);
+
+ bool operator==(const BaseMessage &other) const;
+
+ static void parse(QBuffer *data, QString &parseError, BaseMessage &message);
+ static QTextCodec *defaultCodec();
+
+ bool isComplete() const;
+ bool isValid() const;
+ QByteArray header() const;
+
+ QByteArray mimeType;
+ QByteArray content;
+ int contentLength = -1;
+ QTextCodec *codec = defaultCodec();
+
+private:
+ QByteArray lengthHeader() const;
+ QByteArray typeHeader() const;
+};
+
+} // namespace LanguageClient
diff --git a/src/shared/lsp/callhierarchy.cpp b/src/shared/lsp/callhierarchy.cpp
new file mode 100644
index 000000000..af786fa95
--- /dev/null
+++ b/src/shared/lsp/callhierarchy.cpp
@@ -0,0 +1,28 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "callhierarchy.h"
+
+namespace lsp {
+
+bool CallHierarchyItem::isValid() const
+{
+ return contains(nameKey) && contains(symbolKindKey) && contains(rangeKey) && contains(uriKey)
+ && contains(selectionRangeKey);
+}
+
+PrepareCallHierarchyRequest::PrepareCallHierarchyRequest(const TextDocumentPositionParams &params)
+ : Request(methodName, params)
+{}
+
+CallHierarchyIncomingCallsRequest::CallHierarchyIncomingCallsRequest(
+ const CallHierarchyCallsParams &params)
+ : Request(methodName, params)
+{}
+
+CallHierarchyOutgoingCallsRequest::CallHierarchyOutgoingCallsRequest(
+ const CallHierarchyCallsParams &params)
+ : Request(methodName, params)
+{}
+
+} // namespace lsp
diff --git a/src/shared/lsp/callhierarchy.h b/src/shared/lsp/callhierarchy.h
new file mode 100644
index 000000000..3db1f08de
--- /dev/null
+++ b/src/shared/lsp/callhierarchy.h
@@ -0,0 +1,108 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "jsonrpcmessages.h"
+
+namespace lsp {
+
+class LANGUAGESERVERPROTOCOL_EXPORT CallHierarchyItem : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ QString name() const { return typedValue<QString>(nameKey); }
+ void setName(const QString &name) { insert(nameKey, name); }
+
+ SymbolKind symbolKind() const { return SymbolKind(typedValue<int>(symbolKindKey)); }
+ void setSymbolKind(const SymbolKind &symbolKind) { insert(symbolKindKey, int(symbolKind)); }
+
+ Range range() const { return typedValue<Range>(rangeKey); }
+ void setRange(const Range &range) { insert(rangeKey, range); }
+
+ DocumentUri uri() const { return DocumentUri::fromProtocol(typedValue<QString>(uriKey)); }
+ void setUri(const DocumentUri &uri) { insert(uriKey, uri); }
+
+ Range selectionRange() const { return typedValue<Range>(selectionRangeKey); }
+ void setSelectionRange(Range selectionRange) { insert(selectionRangeKey, selectionRange); }
+
+ std::optional<QString> detail() const { return optionalValue<QString>(detailKey); }
+ void setDetail(const QString &detail) { insert(detailKey, detail); }
+ void clearDetail() { remove(detailKey); }
+
+ std::optional<QList<DocumentSymbol>> children() const
+ { return optionalArray<DocumentSymbol>(childrenKey); }
+ void setChildren(const QList<DocumentSymbol> &children) { insertArray(childrenKey, children); }
+ void clearChildren() { remove(childrenKey); }
+
+ bool isValid() const override;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT PrepareCallHierarchyRequest : public Request<
+ LanguageClientArray<CallHierarchyItem>, std::nullptr_t, TextDocumentPositionParams>
+{
+public:
+ explicit PrepareCallHierarchyRequest(const TextDocumentPositionParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/prepareCallHierarchy";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT CallHierarchyCallsParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ CallHierarchyItem item() const { return typedValue<CallHierarchyItem>(itemKey); }
+ void setItem(const CallHierarchyItem &item) { insert(itemKey, item); }
+
+ bool isValid() const override { return contains(itemKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT CallHierarchyIncomingCall : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ CallHierarchyItem from() const { return typedValue<CallHierarchyItem>(fromKey); }
+ void setFrom(const CallHierarchyItem &from) { insert(fromKey, from); }
+
+ QList<Range> fromRanges() const { return array<Range>(fromRangesKey); }
+ void setFromRanges(const QList<Range> &fromRanges) { insertArray(fromRangesKey, fromRanges); }
+
+ bool isValid() const override { return contains(fromRangesKey) && contains(fromRangesKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT CallHierarchyIncomingCallsRequest : public Request<
+ LanguageClientArray<CallHierarchyIncomingCall>, std::nullptr_t, CallHierarchyCallsParams>
+{
+public:
+ explicit CallHierarchyIncomingCallsRequest(const CallHierarchyCallsParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "callHierarchy/incomingCalls";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT CallHierarchyOutgoingCall : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ CallHierarchyItem to() const { return typedValue<CallHierarchyItem>(toKey); }
+ void setTo(const CallHierarchyItem &to) { insert(toKey, to); }
+
+ QList<Range> fromRanges() const { return array<Range>(fromRangesKey); }
+ void setFromRanges(const QList<Range> &fromRanges) { insertArray(fromRangesKey, fromRanges); }
+
+ bool isValid() const override { return contains(fromRangesKey) && contains(fromRangesKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT CallHierarchyOutgoingCallsRequest : public Request<
+ LanguageClientArray<CallHierarchyOutgoingCall>, std::nullptr_t, CallHierarchyCallsParams>
+{
+public:
+ explicit CallHierarchyOutgoingCallsRequest(const CallHierarchyCallsParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "callHierarchy/outgoingCalls";
+};
+
+} // namespace lsp
diff --git a/src/shared/lsp/client.cpp b/src/shared/lsp/client.cpp
new file mode 100644
index 000000000..8479131a6
--- /dev/null
+++ b/src/shared/lsp/client.cpp
@@ -0,0 +1,17 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "client.h"
+
+namespace lsp {
+
+constexpr const char RegisterCapabilityRequest::methodName[];
+constexpr const char UnregisterCapabilityRequest::methodName[];
+
+RegisterCapabilityRequest::RegisterCapabilityRequest(const RegistrationParams &params)
+ : Request(methodName, params) { }
+
+UnregisterCapabilityRequest::UnregisterCapabilityRequest(const UnregistrationParams &params)
+ : UnregisterCapabilityRequest(methodName, params) { }
+
+} // namespace lsp
diff --git a/src/shared/lsp/client.h b/src/shared/lsp/client.h
new file mode 100644
index 000000000..29ebc5bc6
--- /dev/null
+++ b/src/shared/lsp/client.h
@@ -0,0 +1,94 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "jsonrpcmessages.h"
+
+namespace lsp {
+
+class Registration : public JsonObject
+{
+public:
+ Registration() : Registration(QString()) {}
+ explicit Registration(const QString &method)
+ {
+ setId(QUuid::createUuid().toString());
+ setMethod(method);
+ }
+ using JsonObject::JsonObject;
+
+ QString id() const { return typedValue<QString>(idKey); }
+ void setId(const QString &id) { insert(idKey, id); }
+
+ QString method() const { return typedValue<QString>(methodKey); }
+ void setMethod(const QString &method) { insert(methodKey, method); }
+
+ QJsonValue registerOptions() const { return value(registerOptionsKey); }
+ void setRegisterOptions(const QJsonValue &registerOptions)
+ { insert(registerOptionsKey, registerOptions); }
+
+ bool isValid() const override { return contains(idKey) && contains(methodKey); }
+};
+
+class RegistrationParams : public JsonObject
+{
+public:
+ RegistrationParams() : RegistrationParams(QList<Registration>()) {}
+ explicit RegistrationParams(const QList<Registration> &registrations)
+ { setRegistrations(registrations); }
+ using JsonObject::JsonObject;
+
+ QList<Registration> registrations() const { return array<Registration>(registrationsKey); }
+ void setRegistrations(const QList<Registration> &registrations)
+ { insertArray(registrationsKey, registrations); }
+
+ bool isValid() const override { return contains(registrationsKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT RegisterCapabilityRequest : public Request<
+ std::nullptr_t, std::nullptr_t, RegistrationParams>
+{
+public:
+ explicit RegisterCapabilityRequest(const RegistrationParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "client/registerCapability";
+};
+
+class Unregistration : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ QString id() const { return typedValue<QString>(idKey); }
+ void setId(const QString &id) { insert(idKey, id); }
+
+ QString method() const { return typedValue<QString>(methodKey); }
+ void setMethod(const QString &method) { insert(methodKey, method); }
+
+ bool isValid() const override { return contains(idKey) && contains(methodKey); }
+};
+
+class UnregistrationParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ QList<Unregistration> unregistrations() const
+ { return array<Unregistration>(unregistrationsKey); }
+ void setUnregistrations(const QList<Unregistration> &unregistrations)
+ { insertArray(unregistrationsKey, unregistrations); }
+
+ bool isValid() const override { return contains(unregistrationsKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT UnregisterCapabilityRequest : public Request<
+ std::nullptr_t, std::nullptr_t, UnregistrationParams>
+{
+public:
+ explicit UnregisterCapabilityRequest(const UnregistrationParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "client/unregisterCapability";
+};
+
+} // namespace LanguageClient
diff --git a/src/shared/lsp/clientcapabilities.cpp b/src/shared/lsp/clientcapabilities.cpp
new file mode 100644
index 000000000..34d9de9e7
--- /dev/null
+++ b/src/shared/lsp/clientcapabilities.cpp
@@ -0,0 +1,122 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "clientcapabilities.h"
+
+namespace lsp {
+
+std::optional<QList<SymbolKind>> SymbolCapabilities::SymbolKindCapabilities::valueSet() const
+{
+ if (std::optional<QList<int>> array = optionalArray<int>(valueSetKey)) {
+ return std::make_optional(
+ Utils::transform(*array, [](int value) { return static_cast<SymbolKind>(value); }));
+ }
+ return std::nullopt;
+}
+
+void SymbolCapabilities::SymbolKindCapabilities::setValueSet(const QList<SymbolKind> &valueSet)
+{
+ insert(valueSetKey, enumArrayToJsonArray<SymbolKind>(valueSet));
+}
+
+WorkspaceClientCapabilities::WorkspaceClientCapabilities()
+{
+ setWorkspaceFolders(true);
+}
+
+std::optional<std::variant<bool, QJsonObject>> SemanticTokensClientCapabilities::Requests::range()
+ const
+{
+ using RetType = std::variant<bool, QJsonObject>;
+ const QJsonValue &rangeOptions = value(rangeKey);
+ if (rangeOptions.isBool())
+ return RetType(rangeOptions.toBool());
+ if (rangeOptions.isObject())
+ return RetType(rangeOptions.toObject());
+ return std::nullopt;
+}
+
+void SemanticTokensClientCapabilities::Requests::setRange(
+ const std::variant<bool, QJsonObject> &range)
+{
+ insertVariant<bool, QJsonObject>(rangeKey, range);
+}
+
+std::optional<std::variant<bool, FullSemanticTokenOptions>>
+SemanticTokensClientCapabilities::Requests::full() const
+{
+ using RetType = std::variant<bool, FullSemanticTokenOptions>;
+ const QJsonValue &fullOptions = value(fullKey);
+ if (fullOptions.isBool())
+ return RetType(fullOptions.toBool());
+ if (fullOptions.isObject())
+ return RetType(FullSemanticTokenOptions(fullOptions.toObject()));
+ return std::nullopt;
+}
+
+void SemanticTokensClientCapabilities::Requests::setFull(
+ const std::variant<bool, FullSemanticTokenOptions> &full)
+{
+ insertVariant<bool, FullSemanticTokenOptions>(fullKey, full);
+}
+
+std::optional<SemanticTokensClientCapabilities> TextDocumentClientCapabilities::semanticTokens() const
+{
+ return optionalValue<SemanticTokensClientCapabilities>(semanticTokensKey);
+}
+
+void TextDocumentClientCapabilities::setSemanticTokens(
+ const SemanticTokensClientCapabilities &semanticTokens)
+{
+ insert(semanticTokensKey, semanticTokens);
+}
+
+bool SemanticTokensClientCapabilities::isValid() const
+{
+ return contains(requestsKey) && contains(tokenTypesKey) && contains(tokenModifiersKey)
+ && contains(formatsKey);
+}
+
+const char resourceOperationCreate[] = "create";
+const char resourceOperationRename[] = "rename";
+const char resourceOperationDelete[] = "delete";
+
+std::optional<QList<WorkspaceClientCapabilities::WorkspaceEditCapabilities::ResourceOperationKind>>
+WorkspaceClientCapabilities::WorkspaceEditCapabilities::resourceOperations() const
+{
+ if (!contains(resourceOperationsKey))
+ return std::nullopt;
+ QList<ResourceOperationKind> result;
+ for (const QJsonValue &value : this->value(resourceOperationsKey).toArray()) {
+ const QString str = value.toString();
+ if (str == resourceOperationCreate)
+ result << ResourceOperationKind::Create;
+ else if (str == resourceOperationRename)
+ result << ResourceOperationKind::Rename;
+ else if (str == resourceOperationDelete)
+ result << ResourceOperationKind::Delete;
+ }
+ return result;
+}
+
+void WorkspaceClientCapabilities::WorkspaceEditCapabilities::setResourceOperations(
+ const QList<ResourceOperationKind> &resourceOperations)
+{
+ QJsonArray array;
+ for (const auto &kind : resourceOperations) {
+ switch (kind) {
+ case ResourceOperationKind::Create:
+ array << resourceOperationCreate;
+ break;
+ case ResourceOperationKind::Rename:
+ array << resourceOperationRename;
+ break;
+ case ResourceOperationKind::Delete:
+ array << resourceOperationDelete;
+ break;
+ }
+ }
+ insert(resourceOperationsKey, array);
+}
+
+} // namespace lsp
diff --git a/src/shared/lsp/clientcapabilities.h b/src/shared/lsp/clientcapabilities.h
new file mode 100644
index 000000000..44add0a2c
--- /dev/null
+++ b/src/shared/lsp/clientcapabilities.h
@@ -0,0 +1,674 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "jsonkeys.h"
+#include "lsptypes.h"
+#include "semantictokens.h"
+
+namespace lsp {
+
+class LANGUAGESERVERPROTOCOL_EXPORT DynamicRegistrationCapabilities : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ std::optional<bool> dynamicRegistration() const
+ {
+ return optionalValue<bool>(dynamicRegistrationKey);
+ }
+ void setDynamicRegistration(bool dynamicRegistration) { insert(dynamicRegistrationKey, dynamicRegistration); }
+ void clearDynamicRegistration() { remove(dynamicRegistrationKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT FullSemanticTokenOptions : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ /**
+ * The client will send the `textDocument/semanticTokens/full/delta`
+ * request if the server provides a corresponding handler.
+ */
+ std::optional<bool> delta() const { return optionalValue<bool>(deltaKey); }
+ void setDelta(bool delta) { insert(deltaKey, delta); }
+ void clearDelta() { remove(deltaKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensClientCapabilities : public DynamicRegistrationCapabilities
+{
+public:
+ using DynamicRegistrationCapabilities::DynamicRegistrationCapabilities;
+ class LANGUAGESERVERPROTOCOL_EXPORT Requests : public JsonObject
+ {
+ /**
+ * Which requests the client supports and might send to the server
+ * depending on the server's capability. Please note that clients might not
+ * show semantic tokens or degrade some of the user experience if a range
+ * or full request is advertised by the client but not provided by the
+ * server. If for example the client capability `requests.full` and
+ * `request.range` are both set to true but the server only provides a
+ * range provider the client might not render a minimap correctly or might
+ * even decide to not show any semantic tokens at all.
+ */
+ public:
+ using JsonObject::JsonObject;
+
+ /**
+ * The client will send the `textDocument/semanticTokens/range` request
+ * if the server provides a corresponding handler.
+ */
+ std::optional<std::variant<bool, QJsonObject>> range() const;
+ void setRange(const std::variant<bool, QJsonObject> &range);
+ void clearRange() { remove(rangeKey); }
+
+ /**
+ * The client will send the `textDocument/semanticTokens/full` request
+ * if the server provides a corresponding handler.
+ */
+ std::optional<std::variant<bool, FullSemanticTokenOptions>> full() const;
+ void setFull(const std::variant<bool, FullSemanticTokenOptions> &full);
+ void clearFull() { remove(fullKey); }
+ };
+
+ Requests requests() const { return typedValue<Requests>(requestsKey); }
+ void setRequests(const Requests &requests) { insert(requestsKey, requests); }
+
+ /// The token types that the client supports.
+ QList<QString> tokenTypes() const { return array<QString>(tokenTypesKey); }
+ void setTokenTypes(const QList<QString> &value) { insertArray(tokenTypesKey, value); }
+
+ /// The token modifiers that the client supports.
+ QList<QString> tokenModifiers() const { return array<QString>(tokenModifiersKey); }
+ void setTokenModifiers(const QList<QString> &value) { insertArray(tokenModifiersKey, value); }
+
+ /// The formats the clients supports.
+ QList<QString> formats() const { return array<QString>(formatsKey); }
+ void setFormats(const QList<QString> &value) { insertArray(formatsKey, value); }
+
+ /// Whether the client supports tokens that can overlap each other.
+ std::optional<bool> overlappingTokenSupport() const
+ {
+ return optionalValue<bool>(overlappingTokenSupportKey);
+ }
+ void setOverlappingTokenSupport(bool overlappingTokenSupport) { insert(overlappingTokenSupportKey, overlappingTokenSupport); }
+ void clearOverlappingTokenSupport() { remove(overlappingTokenSupportKey); }
+
+ /// Whether the client supports tokens that can span multiple lines.
+ std::optional<bool> multiLineTokenSupport() const
+ {
+ return optionalValue<bool>(multiLineTokenSupportKey);
+ }
+ void setMultiLineTokenSupport(bool multiLineTokenSupport) { insert(multiLineTokenSupportKey, multiLineTokenSupport); }
+ void clearMultiLineTokenSupport() { remove(multiLineTokenSupportKey); }
+
+ bool isValid() const override;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SymbolCapabilities : public DynamicRegistrationCapabilities
+{
+public:
+ using DynamicRegistrationCapabilities::DynamicRegistrationCapabilities;
+
+ class LANGUAGESERVERPROTOCOL_EXPORT SymbolKindCapabilities : public JsonObject
+ {
+ public:
+ using JsonObject::JsonObject;
+
+ /*
+ * The symbol kind values the client supports. When this
+ * property exists the client also guarantees that it will
+ * handle values outside its set gracefully and falls back
+ * to a default value when unknown.
+ *
+ * If this property is not present the client only supports
+ * the symbol kinds from `File` to `Array` as defined in
+ * the initial version of the protocol.
+ */
+ std::optional<QList<SymbolKind>> valueSet() const;
+ void setValueSet(const QList<SymbolKind> &valueSet);
+ void clearValueSet() { remove(valueSetKey); }
+ };
+
+ // Specific capabilities for the `SymbolKind` in the `workspace/symbol` request.
+ std::optional<SymbolKindCapabilities> symbolKind() const
+ { return optionalValue<SymbolKindCapabilities>(symbolKindKey); }
+ void setSymbolKind(const SymbolKindCapabilities &symbolKind) { insert(symbolKindKey, symbolKind); }
+ void clearSymbolKind() { remove(symbolKindKey); }
+
+ std::optional<bool> hierarchicalDocumentSymbolSupport() const
+ { return optionalValue<bool>(hierarchicalDocumentSymbolSupportKey); }
+ void setHierarchicalDocumentSymbolSupport(bool hierarchicalDocumentSymbolSupport)
+ { insert(hierarchicalDocumentSymbolSupportKey, hierarchicalDocumentSymbolSupport); }
+ void clearHierachicalDocumentSymbolSupport() { remove(hierarchicalDocumentSymbolSupportKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentClientCapabilities : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ class LANGUAGESERVERPROTOCOL_EXPORT SynchronizationCapabilities : public DynamicRegistrationCapabilities
+ {
+ public:
+ using DynamicRegistrationCapabilities::DynamicRegistrationCapabilities;
+
+ // The client supports sending will save notifications.
+ std::optional<bool> willSave() const { return optionalValue<bool>(willSaveKey); }
+ void setWillSave(bool willSave) { insert(willSaveKey, willSave); }
+ void clearWillSave() { remove(willSaveKey); }
+
+ /*
+ * The client supports sending a will save request and
+ * waits for a response providing text edits which will
+ * be applied to the document before it is saved.
+ */
+ std::optional<bool> willSaveWaitUntil() const
+ { return optionalValue<bool>(willSaveWaitUntilKey); }
+ void setWillSaveWaitUntil(bool willSaveWaitUntil)
+ { insert(willSaveWaitUntilKey, willSaveWaitUntil); }
+ void clearWillSaveWaitUntil() { remove(willSaveWaitUntilKey); }
+
+ // The client supports did save notifications.
+ std::optional<bool> didSave() const { return optionalValue<bool>(didSaveKey); }
+ void setDidSave(bool didSave) { insert(didSaveKey, didSave); }
+ void clearDidSave() { remove(didSaveKey); }
+ };
+
+ std::optional<SynchronizationCapabilities> synchronization() const
+ { return optionalValue<SynchronizationCapabilities>(synchronizationKey); }
+ void setSynchronization(const SynchronizationCapabilities &synchronization)
+ { insert(synchronizationKey, synchronization); }
+ void clearSynchronization() { remove(synchronizationKey); }
+
+ class LANGUAGESERVERPROTOCOL_EXPORT CompletionCapabilities : public DynamicRegistrationCapabilities
+ {
+ public:
+ using DynamicRegistrationCapabilities::DynamicRegistrationCapabilities;
+
+ class LANGUAGESERVERPROTOCOL_EXPORT CompletionItemCapbilities : public JsonObject
+ {
+ public:
+ using JsonObject::JsonObject;
+
+ /*
+ * Client supports snippets as insert text.
+ *
+ * A snippet can define tab stops and placeholders with `$1`, `$2`
+ * and `${3:foo}`. `$0` defines the final tab stop, it defaults to
+ * the end of the snippet. Placeholders with equal identifiers are linked,
+ * that is typing in one will update others too.
+ */
+ std::optional<bool> snippetSupport() const
+ { return optionalValue<bool>(snippetSupportKey); }
+ void setSnippetSupport(bool snippetSupport)
+ { insert(snippetSupportKey, snippetSupport); }
+ void clearSnippetSupport() { remove(snippetSupportKey); }
+
+ // Client supports commit characters on a completion item.
+ std::optional<bool> commitCharacterSupport() const
+ { return optionalValue<bool>(commitCharacterSupportKey); }
+ void setCommitCharacterSupport(bool commitCharacterSupport)
+ { insert(commitCharacterSupportKey, commitCharacterSupport); }
+ void clearCommitCharacterSupport() { remove(commitCharacterSupportKey); }
+
+ /*
+ * Client supports the follow content formats for the documentation
+ * property. The order describes the preferred format of the client.
+ */
+ std::optional<QList<MarkupKind>> documentationFormat() const;
+ void setDocumentationFormat(const QList<MarkupKind> &documentationFormat);
+ void clearDocumentationFormat() { remove(documentationFormatKey); }
+ };
+
+ // The client supports the following `CompletionItem` specific capabilities.
+ std::optional<CompletionItemCapbilities> completionItem() const
+ { return optionalValue<CompletionItemCapbilities>(completionItemKey); }
+ void setCompletionItem(const CompletionItemCapbilities &completionItem)
+ { insert(completionItemKey, completionItem); }
+ void clearCompletionItem() { remove(completionItemKey); }
+
+ class LANGUAGESERVERPROTOCOL_EXPORT CompletionItemKindCapabilities : public JsonObject
+ {
+ public:
+ CompletionItemKindCapabilities();
+ using JsonObject::JsonObject;
+ /*
+ * The completion item kind values the client supports. When this
+ * property exists the client also guarantees that it will
+ * handle values outside its set gracefully and falls back
+ * to a default value when unknown.
+ *
+ * If this property is not present the client only supports
+ * the completion items kinds from `Text` to `Reference` as defined in
+ * the initial version of the protocol.
+ */
+ std::optional<QList<CompletionItemKind::Kind>> valueSet() const;
+ void setValueSet(const QList<CompletionItemKind::Kind> &valueSet);
+ void clearValueSet() { remove(valueSetKey); }
+ };
+
+ std::optional<CompletionItemKindCapabilities> completionItemKind() const
+ { return optionalValue<CompletionItemKindCapabilities>(completionItemKindKey); }
+ void setCompletionItemKind(const CompletionItemKindCapabilities &completionItemKind)
+ { insert(completionItemKindKey, completionItemKind); }
+ void clearCompletionItemKind() { remove(completionItemKindKey); }
+
+ /*
+ * The client supports to send additional context information for a
+ * `textDocument/completion` request.
+ */
+ std::optional<bool> contextSupport() const
+ {
+ return optionalValue<bool>(contextSupportKey);
+ }
+ void setContextSupport(bool contextSupport) { insert(contextSupportKey, contextSupport); }
+ void clearContextSupport() { remove(contextSupportKey); }
+ };
+
+ // Capabilities specific to the `textDocument/completion`
+ std::optional<CompletionCapabilities> completion() const
+ { return optionalValue<CompletionCapabilities>(completionKey); }
+ void setCompletion(const CompletionCapabilities &completion)
+ { insert(completionKey, completion); }
+ void clearCompletion() { remove(completionKey); }
+
+ class LANGUAGESERVERPROTOCOL_EXPORT HoverCapabilities : public DynamicRegistrationCapabilities
+ {
+ public:
+ using DynamicRegistrationCapabilities::DynamicRegistrationCapabilities;
+ /*
+ * Client supports the follow content formats for the content
+ * property. The order describes the preferred format of the client.
+ */
+ std::optional<QList<MarkupKind>> contentFormat() const;
+ void setContentFormat(const QList<MarkupKind> &contentFormat);
+ void clearContentFormat() { remove(contentFormatKey); }
+ };
+
+ std::optional<HoverCapabilities> hover() const
+ {
+ return optionalValue<HoverCapabilities>(hoverKey);
+ }
+ void setHover(const HoverCapabilities &hover) { insert(hoverKey, hover); }
+ void clearHover() { remove(hoverKey); }
+
+ class LANGUAGESERVERPROTOCOL_EXPORT SignatureHelpCapabilities : public DynamicRegistrationCapabilities
+ {
+ public:
+ using DynamicRegistrationCapabilities::DynamicRegistrationCapabilities;
+
+ class LANGUAGESERVERPROTOCOL_EXPORT SignatureInformationCapabilities : public JsonObject
+ {
+ public:
+ using JsonObject::JsonObject;
+ /*
+ * Client supports the follow content formats for the documentation
+ * property. The order describes the preferred format of the client.
+ */
+ std::optional<QList<MarkupKind>> documentationFormat() const;
+ void setDocumentationFormat(const QList<MarkupKind> &documentationFormat);
+ void clearDocumentationFormat() { remove(documentationFormatKey); }
+
+ std::optional<bool> activeParameterSupport() const
+ { return optionalValue<bool>(activeParameterSupportKey); }
+ void setActiveParameterSupport(bool activeParameterSupport)
+ { insert(activeParameterSupportKey, activeParameterSupport); }
+ void clearActiveParameterSupport() { remove(activeParameterSupportKey); }
+ };
+
+ // The client supports the following `SignatureInformation` specific properties.
+ std::optional<SignatureInformationCapabilities> signatureInformation() const
+ { return optionalValue<SignatureInformationCapabilities>(signatureInformationKey); }
+ void setSignatureInformation(const SignatureInformationCapabilities &signatureInformation)
+ { insert(signatureInformationKey, signatureInformation); }
+ void clearSignatureInformation() { remove(signatureInformationKey); }
+ };
+
+ // Capabilities specific to the `textDocument/signatureHelp`
+ std::optional<SignatureHelpCapabilities> signatureHelp() const
+ { return optionalValue<SignatureHelpCapabilities>(signatureHelpKey); }
+ void setSignatureHelp(const SignatureHelpCapabilities &signatureHelp)
+ { insert(signatureHelpKey, signatureHelp); }
+ void clearSignatureHelp() { remove(signatureHelpKey); }
+
+ // Whether references supports dynamic registration.
+ std::optional<DynamicRegistrationCapabilities> references() const
+ { return optionalValue<DynamicRegistrationCapabilities>(referencesKey); }
+ void setReferences(const DynamicRegistrationCapabilities &references)
+ { insert(referencesKey, references); }
+ void clearReferences() { remove(referencesKey); }
+
+ // Whether document highlight supports dynamic registration.
+ std::optional<DynamicRegistrationCapabilities> documentHighlight() const
+ { return optionalValue<DynamicRegistrationCapabilities>(documentHighlightKey); }
+ void setDocumentHighlight(const DynamicRegistrationCapabilities &documentHighlight)
+ { insert(documentHighlightKey, documentHighlight); }
+ void clearDocumentHighlight() { remove(documentHighlightKey); }
+
+ // Capabilities specific to the `textDocument/documentSymbol`
+ std::optional<SymbolCapabilities> documentSymbol() const
+ { return optionalValue<SymbolCapabilities>(documentSymbolKey); }
+ void setDocumentSymbol(const SymbolCapabilities &documentSymbol)
+ { insert(documentSymbolKey, documentSymbol); }
+ void clearDocumentSymbol() { remove(documentSymbolKey); }
+
+ // Whether formatting supports dynamic registration.
+ std::optional<DynamicRegistrationCapabilities> formatting() const
+ { return optionalValue<DynamicRegistrationCapabilities>(formattingKey); }
+ void setFormatting(const DynamicRegistrationCapabilities &formatting)
+ { insert(formattingKey, formatting); }
+ void clearFormatting() { remove(formattingKey); }
+
+ // Whether range formatting supports dynamic registration.
+ std::optional<DynamicRegistrationCapabilities> rangeFormatting() const
+ { return optionalValue<DynamicRegistrationCapabilities>(rangeFormattingKey); }
+ void setRangeFormatting(const DynamicRegistrationCapabilities &rangeFormatting)
+ { insert(rangeFormattingKey, rangeFormatting); }
+ void clearRangeFormatting() { remove(rangeFormattingKey); }
+
+ // Whether on type formatting supports dynamic registration.
+ std::optional<DynamicRegistrationCapabilities> onTypeFormatting() const
+ { return optionalValue<DynamicRegistrationCapabilities>(onTypeFormattingKey); }
+ void setOnTypeFormatting(const DynamicRegistrationCapabilities &onTypeFormatting)
+ { insert(onTypeFormattingKey, onTypeFormatting); }
+ void clearOnTypeFormatting() { remove(onTypeFormattingKey); }
+
+ // Whether definition supports dynamic registration.
+ std::optional<DynamicRegistrationCapabilities> definition() const
+ { return optionalValue<DynamicRegistrationCapabilities>(definitionKey); }
+ void setDefinition(const DynamicRegistrationCapabilities &definition)
+ { insert(definitionKey, definition); }
+ void clearDefinition() { remove(definitionKey); }
+
+ /*
+ * Whether typeDefinition supports dynamic registration. If this is set to `true`
+ * the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
+ * return value for the corresponding server capability as well.
+ */
+ std::optional<DynamicRegistrationCapabilities> typeDefinition() const
+ { return optionalValue<DynamicRegistrationCapabilities>(typeDefinitionKey); }
+ void setTypeDefinition(const DynamicRegistrationCapabilities &typeDefinition)
+ { insert(typeDefinitionKey, typeDefinition); }
+ void clearTypeDefinition() { remove(typeDefinitionKey); }
+
+ /*
+ * Whether implementation supports dynamic registration. If this is set to `true`
+ * the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
+ * return value for the corresponding server capability as well.
+ */
+ std::optional<DynamicRegistrationCapabilities> implementation() const
+ { return optionalValue<DynamicRegistrationCapabilities>(implementationKey); }
+ void setImplementation(const DynamicRegistrationCapabilities &implementation)
+ { insert(implementationKey, implementation); }
+ void clearImplementation() { remove(implementationKey); }
+
+ class LANGUAGESERVERPROTOCOL_EXPORT CodeActionCapabilities : public DynamicRegistrationCapabilities
+ {
+ public:
+ using DynamicRegistrationCapabilities::DynamicRegistrationCapabilities;
+
+ class LANGUAGESERVERPROTOCOL_EXPORT CodeActionLiteralSupport : public JsonObject
+ {
+ public:
+ using JsonObject::JsonObject;
+
+ class LANGUAGESERVERPROTOCOL_EXPORT CodeActionKind : public JsonObject
+ {
+ public:
+ using JsonObject::JsonObject;
+ CodeActionKind() : CodeActionKind(QList<QString>()) {}
+ explicit CodeActionKind(const QList<QString> &kinds) { setValueSet(kinds); }
+
+ QList<QString> valueSet() const { return array<QString>(valueSetKey); }
+ void setValueSet(const QList<QString> &valueSet)
+ { insertArray(valueSetKey, valueSet); }
+
+ bool isValid() const override { return contains(valueSetKey); }
+ };
+
+ CodeActionKind codeActionKind() const
+ { return typedValue<CodeActionKind>(codeActionKindKey); }
+ void setCodeActionKind(const CodeActionKind &codeActionKind)
+ { insert(codeActionKindKey, codeActionKind); }
+
+ bool isValid() const override { return contains(codeActionKindKey); }
+ };
+
+ std::optional<CodeActionLiteralSupport> codeActionLiteralSupport() const
+ { return optionalValue<CodeActionLiteralSupport>(codeActionLiteralSupportKey); }
+ void setCodeActionLiteralSupport(const CodeActionLiteralSupport &codeActionLiteralSupport)
+ { insert(codeActionLiteralSupportKey, codeActionLiteralSupport); }
+ void clearCodeActionLiteralSupport() { remove(codeActionLiteralSupportKey); }
+ };
+
+ // Whether code action supports dynamic registration.
+ std::optional<CodeActionCapabilities> codeAction() const
+ { return optionalValue<CodeActionCapabilities>(codeActionKey); }
+ void setCodeAction(const CodeActionCapabilities &codeAction)
+ { insert(codeActionKey, codeAction); }
+ void clearCodeAction() { remove(codeActionKey); }
+
+ // Whether code lens supports dynamic registration.
+ std::optional<DynamicRegistrationCapabilities> codeLens() const
+ { return optionalValue<DynamicRegistrationCapabilities>(codeLensKey); }
+ void setCodeLens(const DynamicRegistrationCapabilities &codeLens)
+ { insert(codeLensKey, codeLens); }
+ void clearCodeLens() { remove(codeLensKey); }
+
+ // Whether document link supports dynamic registration.
+ std::optional<DynamicRegistrationCapabilities> documentLink() const
+ { return optionalValue<DynamicRegistrationCapabilities>(documentLinkKey); }
+ void setDocumentLink(const DynamicRegistrationCapabilities &documentLink)
+ { insert(documentLinkKey, documentLink); }
+ void clearDocumentLink() { remove(documentLinkKey); }
+
+ /*
+ * Whether colorProvider supports dynamic registration. If this is set to `true`
+ * the client supports the new `(ColorProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)`
+ * return value for the corresponding server capability as well.
+ */
+ std::optional<DynamicRegistrationCapabilities> colorProvider() const
+ { return optionalValue<DynamicRegistrationCapabilities>(colorProviderKey); }
+ void setColorProvider(const DynamicRegistrationCapabilities &colorProvider)
+ { insert(colorProviderKey, colorProvider); }
+ void clearColorProvider() { remove(colorProviderKey); }
+
+ class LANGUAGESERVERPROTOCOL_EXPORT RenameClientCapabilities : public DynamicRegistrationCapabilities
+ {
+ public:
+ using DynamicRegistrationCapabilities::DynamicRegistrationCapabilities;
+ /**
+ * Client supports testing for validity of rename operations
+ * before execution.
+ *
+ * @since version 3.12.0
+ */
+
+ std::optional<bool> prepareSupport() const
+ {
+ return optionalValue<bool>(prepareSupportKey);
+ }
+ void setPrepareSupport(bool prepareSupport) { insert(prepareSupportKey, prepareSupport); }
+ void clearPrepareSupport() { remove(prepareSupportKey); }
+ };
+
+ // Whether rename supports dynamic registration.
+ std::optional<RenameClientCapabilities> rename() const
+ { return optionalValue<RenameClientCapabilities>(renameKey); }
+ void setRename(const RenameClientCapabilities &rename)
+ { insert(renameKey, rename); }
+ void clearRename() { remove(renameKey); }
+
+ std::optional<SemanticTokensClientCapabilities> semanticTokens() const;
+ void setSemanticTokens(const SemanticTokensClientCapabilities &semanticTokens);
+ void clearSemanticTokens() { remove(semanticTokensKey); }
+
+ std::optional<DynamicRegistrationCapabilities> callHierarchy() const
+ { return optionalValue<DynamicRegistrationCapabilities>(callHierarchyKey); }
+ void setCallHierarchy(const DynamicRegistrationCapabilities &callHierarchy)
+ { insert(callHierarchyKey, callHierarchy); }
+ void clearCallHierarchy() { remove(callHierarchyKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensWorkspaceClientCapabilities : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+ /**
+ * Whether the client implementation supports a refresh request sent from
+ * the server to the client.
+ *
+ * Note that this event is global and will force the client to refresh all
+ * semantic tokens currently shown. It should be used with absolute care
+ * and is useful for situation where a server for example detect a project
+ * wide change that requires such a calculation.
+ */
+ std::optional<bool> refreshSupport() const { return optionalValue<bool>(refreshSupportKey); }
+ void setRefreshSupport(bool refreshSupport) { insert(refreshSupportKey, refreshSupport); }
+ void clearRefreshSupport() { remove(refreshSupportKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkspaceClientCapabilities : public JsonObject
+{
+public:
+ WorkspaceClientCapabilities();
+ using JsonObject::JsonObject;
+
+ /*
+ * The client supports applying batch edits to the workspace by supporting the request
+ * 'workspace/applyEdit'
+ */
+ std::optional<bool> applyEdit() const { return optionalValue<bool>(applyEditKey); }
+ void setApplyEdit(bool applyEdit) { insert(applyEditKey, applyEdit); }
+ void clearApplyEdit() { remove(applyEditKey); }
+
+ class LANGUAGESERVERPROTOCOL_EXPORT WorkspaceEditCapabilities : public JsonObject
+ {
+ public:
+ using JsonObject::JsonObject;
+
+ // The client supports versioned document changes in `WorkspaceEdit`s
+ std::optional<bool> documentChanges() const
+ { return optionalValue<bool>(documentChangesKey); }
+ void setDocumentChanges(bool documentChanges)
+ { insert(documentChangesKey, documentChanges); }
+ void clearDocumentChanges() { remove(documentChangesKey); }
+
+ enum class ResourceOperationKind { Create, Rename, Delete };
+
+ // The resource operations the client supports. Clients should at least support 'create',
+ // 'rename' and 'delete' files and folders.
+ std::optional<QList<ResourceOperationKind>> resourceOperations() const;
+ void setResourceOperations(const QList<ResourceOperationKind> &resourceOperations);
+ void clearResourceOperations() { remove(resourceOperationsKey); }
+ };
+
+ // Capabilities specific to `WorkspaceEdit`s
+ std::optional<WorkspaceEditCapabilities> workspaceEdit() const
+ { return optionalValue<WorkspaceEditCapabilities>(workspaceEditKey); }
+ void setWorkspaceEdit(const WorkspaceEditCapabilities &workspaceEdit)
+ { insert(workspaceEditKey, workspaceEdit); }
+ void clearWorkspaceEdit() { remove(workspaceEditKey); }
+
+ // Capabilities specific to the `workspace/didChangeConfiguration` notification.
+ std::optional<DynamicRegistrationCapabilities> didChangeConfiguration() const
+ { return optionalValue<DynamicRegistrationCapabilities>(didChangeConfigurationKey); }
+ void setDidChangeConfiguration(const DynamicRegistrationCapabilities &didChangeConfiguration)
+ { insert(didChangeConfigurationKey, didChangeConfiguration); }
+ void clearDidChangeConfiguration() { remove(didChangeConfigurationKey); }
+
+ // Capabilities specific to the `workspace/didChangeWatchedFiles` notification.
+ std::optional<DynamicRegistrationCapabilities> didChangeWatchedFiles() const
+ { return optionalValue<DynamicRegistrationCapabilities>(didChangeWatchedFilesKey); }
+ void setDidChangeWatchedFiles(const DynamicRegistrationCapabilities &didChangeWatchedFiles)
+ { insert(didChangeWatchedFilesKey, didChangeWatchedFiles); }
+ void clearDidChangeWatchedFiles() { remove(didChangeWatchedFilesKey); }
+
+ // Specific capabilities for the `SymbolKind` in the `workspace/symbol` request.
+ std::optional<SymbolCapabilities> symbol() const
+ { return optionalValue<SymbolCapabilities>(symbolKey); }
+ void setSymbol(const SymbolCapabilities &symbol) { insert(symbolKey, symbol); }
+ void clearSymbol() { remove(symbolKey); }
+
+ // Capabilities specific to the `workspace/executeCommand` request.
+ std::optional<DynamicRegistrationCapabilities> executeCommand() const
+ { return optionalValue<DynamicRegistrationCapabilities>(executeCommandKey); }
+ void setExecuteCommand(const DynamicRegistrationCapabilities &executeCommand)
+ { insert(executeCommandKey, executeCommand); }
+ void clearExecuteCommand() { remove(executeCommandKey); }
+
+ // The client has support for workspace folders. Since 3.6.0
+ std::optional<bool> workspaceFolders() const
+ { return optionalValue<bool>(workspaceFoldersKey); }
+ void setWorkspaceFolders(bool workspaceFolders)
+ { insert(workspaceFoldersKey, workspaceFolders); }
+ void clearWorkspaceFolders() { remove(workspaceFoldersKey); }
+
+ // The client supports `workspace/configuration` requests. Since 3.6.0
+ std::optional<bool> configuration() const { return optionalValue<bool>(configurationKey); }
+ void setConfiguration(bool configuration) { insert(configurationKey, configuration); }
+ void clearConfiguration() { remove(configurationKey); }
+
+ std::optional<SemanticTokensWorkspaceClientCapabilities> semanticTokens() const
+ { return optionalValue<SemanticTokensWorkspaceClientCapabilities>(semanticTokensKey); }
+ void setSemanticTokens(const SemanticTokensWorkspaceClientCapabilities &semanticTokens)
+ { insert(semanticTokensKey, semanticTokens); }
+ void clearSemanticTokens() { remove(semanticTokensKey); }
+};
+
+class WindowClientClientCapabilities : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ /**
+ * Whether client supports handling progress notifications.
+ * If set, servers are allowed to report in `workDoneProgress` property
+ * in the request specific server capabilities.
+ *
+ */
+ std::optional<bool> workDoneProgress() const
+ { return optionalValue<bool>(workDoneProgressKey); }
+ void setWorkDoneProgress(bool workDoneProgress)
+ { insert(workDoneProgressKey, workDoneProgress); }
+ void clearWorkDoneProgress() { remove(workDoneProgressKey); }
+
+private:
+ constexpr static const char workDoneProgressKey[] = "workDoneProgress";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ClientCapabilities : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ // Workspace specific client capabilities.
+ std::optional<WorkspaceClientCapabilities> workspace() const
+ { return optionalValue<WorkspaceClientCapabilities>(workspaceKey); }
+ void setWorkspace(const WorkspaceClientCapabilities &workspace)
+ { insert(workspaceKey, workspace); }
+ void clearWorkspace() { remove(workspaceKey); }
+
+ // Text document specific client capabilities.
+ std::optional<TextDocumentClientCapabilities> textDocument() const
+ { return optionalValue<TextDocumentClientCapabilities>(textDocumentKey); }
+ void setTextDocument(const TextDocumentClientCapabilities &textDocument)
+ { insert(textDocumentKey, textDocument); }
+ void clearTextDocument() { remove(textDocumentKey); }
+
+ // Window specific client capabilities.
+ std::optional<WindowClientClientCapabilities> window() const
+ { return optionalValue<WindowClientClientCapabilities>(windowKey); }
+ void setWindow(const WindowClientClientCapabilities &window)
+ { insert(windowKey, window); }
+ void clearWindow() { remove(windowKey); }
+
+ // Experimental client capabilities.
+ QJsonValue experimental() const { return value(experimentalKey); }
+ void setExperimental(const QJsonValue &experimental) { insert(experimentalKey, experimental); }
+ void clearExperimental() { remove(experimentalKey); }
+};
+
+} // namespace lsp
diff --git a/src/shared/lsp/completion.cpp b/src/shared/lsp/completion.cpp
new file mode 100644
index 000000000..48a2ac868
--- /dev/null
+++ b/src/shared/lsp/completion.cpp
@@ -0,0 +1,59 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "completion.h"
+
+namespace lsp {
+
+constexpr const char CompletionRequest::methodName[];
+constexpr const char CompletionItemResolveRequest::methodName[];
+
+CompletionRequest::CompletionRequest(const CompletionParams &params)
+ : Request(methodName, params)
+{ }
+
+std::optional<MarkupOrString> CompletionItem::documentation() const
+{
+ QJsonValue documentation = value(documentationKey);
+ if (documentation.isUndefined())
+ return std::nullopt;
+ return MarkupOrString(documentation);
+}
+
+std::optional<CompletionItem::InsertTextFormat> CompletionItem::insertTextFormat() const
+{
+ if (std::optional<int> value = optionalValue<int>(insertTextFormatKey))
+ return std::make_optional(CompletionItem::InsertTextFormat(*value));
+ return std::nullopt;
+}
+
+std::optional<QList<CompletionItem::CompletionItemTag>> CompletionItem::tags() const
+{
+ if (const auto value = optionalValue<QJsonArray>(tagsKey)) {
+ QList<CompletionItemTag> tags;
+ for (auto it = value->cbegin(); it != value->cend(); ++it)
+ tags << static_cast<CompletionItemTag>(it->toInt());
+ return tags;
+ }
+ return {};
+}
+
+CompletionItemResolveRequest::CompletionItemResolveRequest(const CompletionItem &params)
+ : Request(methodName, params)
+{ }
+
+CompletionResult::CompletionResult(const QJsonValue &value)
+{
+ if (value.isNull()) {
+ emplace<std::nullptr_t>(nullptr);
+ } else if (value.isArray()) {
+ QList<CompletionItem> items;
+ for (auto arrayElement : value.toArray())
+ items << CompletionItem(arrayElement);
+ emplace<QList<CompletionItem>>(items);
+ } else if (value.isObject()) {
+ emplace<CompletionList>(CompletionList(value));
+ }
+}
+
+} // namespace lsp
diff --git a/src/shared/lsp/completion.h b/src/shared/lsp/completion.h
new file mode 100644
index 000000000..665b5a5ae
--- /dev/null
+++ b/src/shared/lsp/completion.h
@@ -0,0 +1,269 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "jsonrpcmessages.h"
+#include "languagefeatures.h"
+
+namespace lsp {
+
+class LANGUAGESERVERPROTOCOL_EXPORT CompletionParams : public TextDocumentPositionParams
+{
+public:
+ using TextDocumentPositionParams::TextDocumentPositionParams;
+
+ enum CompletionTriggerKind {
+ /**
+ * Completion was triggered by typing an identifier (24x7 code
+ * complete), manual invocation (e.g Ctrl+Space) or via API.
+ */
+ Invoked = 1,
+ /**
+ * Completion was triggered by a trigger character specified by
+ * the `triggerCharacters` properties of the `CompletionRegistrationOptions`.
+ */
+ TriggerCharacter = 2,
+ /// Completion was re-triggered as the current completion list is incomplete.
+ TriggerForIncompleteCompletions = 3
+ };
+
+ class CompletionContext : public JsonObject
+ {
+ public:
+ using JsonObject::JsonObject;
+
+ /// How the completion was triggered.
+ CompletionTriggerKind triggerKind() const
+ { return CompletionTriggerKind(typedValue<int>(triggerKindKey)); }
+ void setTriggerKind(CompletionTriggerKind triggerKind)
+ { insert(triggerKindKey, triggerKind); }
+
+ /**
+ * The trigger character (a single character) that has trigger code complete.
+ * Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter`
+ */
+ std::optional<QString> triggerCharacter() const
+ { return optionalValue<QString>(triggerCharacterKey); }
+ void setTriggerCharacter(const QString &triggerCharacter)
+ { insert(triggerCharacterKey, triggerCharacter); }
+ void clearTriggerCharacter() { remove(triggerCharacterKey); }
+
+ bool isValid() const override { return contains(triggerKindKey); }
+ };
+
+ /**
+ * The completion context. This is only available it the client specifies
+ * to send this using `ClientCapabilities.textDocument.completion.contextSupport === true`
+ */
+ std::optional<CompletionContext> context() const
+ { return optionalValue<CompletionContext>(contextKey); }
+ void setContext(const CompletionContext &context)
+ { insert(contextKey, context); }
+ void clearContext() { remove(contextKey); }
+
+ // clangd extension
+ void setLimit(int limit) { insert(limitKey, limit); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT CompletionItem : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ /**
+ * The label of this completion item. By default also the text that is inserted when selecting
+ * this completion.
+ */
+ QString label() const { return typedValue<QString>(labelKey); }
+ void setLabel(const QString &label) { insert(labelKey, label); }
+
+ /// The kind of this completion item. Based of the kind an icon is chosen by the editor.
+ std::optional<int> kind() const { return optionalValue<int>(kindKey); }
+ void setKind(int kind) { insert(kindKey, kind); }
+ void clearKind() { remove(kindKey); }
+
+ /// A human-readable string with additional information about this item, like type information.
+ std::optional<QString> detail() const { return optionalValue<QString>(detailKey); }
+ void setDetail(const QString &detail) { insert(detailKey, detail); }
+ void clearDetail() { remove(detailKey); }
+
+ /// A human-readable string that represents a doc-comment.
+ std::optional<MarkupOrString> documentation() const;
+ void setDocumentation(const MarkupOrString &documentation)
+ { insert(documentationKey, documentation.toJson()); }
+ void cleatDocumentation() { remove(documentationKey); }
+
+ /// A string that should be used when comparing this item
+ /// with other items. When `falsy` the label is used.
+ std::optional<QString> sortText() const { return optionalValue<QString>(sortTextKey); }
+ void setSortText(const QString &sortText) { insert(sortTextKey, sortText); }
+ void clearSortText() { remove(sortTextKey); }
+
+ /// A string that should be used when filtering a set of
+ /// completion items. When `falsy` the label is used.
+ std::optional<QString> filterText() const { return optionalValue<QString>(filterTextKey); }
+ void setFilterText(const QString &filterText) { insert(filterTextKey, filterText); }
+ void clearFilterText() { remove(filterTextKey); }
+
+ /**
+ * A string that should be inserted into a document when selecting
+ * this completion. When `falsy` the label is used.
+ *
+ * The `insertText` is subject to interpretation by the client side.
+ * Some tools might not take the string literally. For example
+ * VS Code when code complete is requested in this example `con<cursor position>`
+ * and a completion item with an `insertText` of `console` is provided it
+ * will only insert `sole`. Therefore it is recommended to use `textEdit` instead
+ * since it avoids additional client side interpretation.
+ *
+ * @deprecated Use textEdit instead.
+ */
+ std::optional<QString> insertText() const { return optionalValue<QString>(insertTextKey); }
+ void setInsertText(const QString &insertText) { insert(insertTextKey, insertText); }
+ void clearInsertText() { remove(insertTextKey); }
+
+ enum InsertTextFormat {
+ /// The primary text to be inserted is treated as a plain string.
+ PlainText = 1,
+
+ /**
+ * The primary text to be inserted is treated as a snippet.
+ *
+ * A snippet can define tab stops and placeholders with `$1`, `$2`
+ * and `${3:foo}`. `$0` defines the final tab stop, it defaults to
+ * the end of the snippet. Placeholders with equal identifiers are linked,
+ * that is typing in one will update others too.
+ */
+ Snippet = 2
+ };
+
+ /// The format of the insert text. The format applies to both the `insertText` property
+ /// and the `newText` property of a provided `textEdit`.
+ std::optional<InsertTextFormat> insertTextFormat() const;
+ void setInsertTextFormat(const InsertTextFormat &insertTextFormat)
+ { insert(insertTextFormatKey, insertTextFormat); }
+ void clearInsertTextFormat() { remove(insertTextFormatKey); }
+
+ /**
+ * An edit which is applied to a document when selecting this completion. When an edit is provided the value of
+ * `insertText` is ignored.
+ *
+ * *Note:* The range of the edit must be a single line range and it must contain the position at which completion
+ * has been requested.
+ */
+ std::optional<TextEdit> textEdit() const { return optionalValue<TextEdit>(textEditKey); }
+ void setTextEdit(const TextEdit &textEdit) { insert(textEditKey, textEdit); }
+ void clearTextEdit() { remove(textEditKey); }
+
+ /**
+ * An optional array of additional text edits that are applied when
+ * selecting this completion. Edits must not overlap with the main edit
+ * nor with themselves.
+ */
+ std::optional<QList<TextEdit>> additionalTextEdits() const
+ { return optionalArray<TextEdit>(additionalTextEditsKey); }
+ void setAdditionalTextEdits(const QList<TextEdit> &additionalTextEdits)
+ { insertArray(additionalTextEditsKey, additionalTextEdits); }
+ void clearAdditionalTextEdits() { remove(additionalTextEditsKey); }
+
+ /**
+ * An optional set of characters that when pressed while this completion is active will accept it first and
+ * then type that character. *Note* that all commit characters should have `length=1` and that superfluous
+ * characters will be ignored.
+ */
+ std::optional<QList<QString>> commitCharacters() const
+ { return optionalArray<QString>(commitCharactersKey); }
+ void setCommitCharacters(const QList<QString> &commitCharacters)
+ { insertArray(commitCharactersKey, commitCharacters); }
+ void clearCommitCharacters() { remove(commitCharactersKey); }
+
+ /**
+ * An optional command that is executed *after* inserting this completion. *Note* that
+ * additional modifications to the current document should be described with the
+ * additionalTextEdits-property.
+ */
+ std::optional<Command> command() const { return optionalValue<Command>(commandKey); }
+ void setCommand(const Command &command) { insert(commandKey, command); }
+ void clearCommand() { remove(commandKey); }
+
+ /**
+ * An data entry field that is preserved on a completion item between
+ * a completion and a completion resolve request.
+ */
+ std::optional<QJsonValue> data() const { return optionalValue<QJsonValue>(dataKey); }
+ void setData(const QJsonValue &data) { insert(dataKey, data); }
+ void clearData() { remove(dataKey); }
+
+ /**
+ * Completion item tags are extra annotations that tweak the rendering of a
+ * completion item.
+ * @since 3.15.0
+ */
+ enum CompletionItemTag {
+ Deprecated = 1,
+ };
+
+ /**
+ * Tags for this completion item.
+ * @since 3.15.0
+ */
+ std::optional<QList<CompletionItemTag>> tags() const;
+
+ /**
+ * Indicates if this item is deprecated.
+ * @deprecated Use `tags` instead if supported.
+ */
+ std::optional<bool> deprecated() const { return optionalValue<bool>(deprecatedKey); }
+
+ bool isValid() const override { return contains(labelKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT CompletionList : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ /**
+ * This list it not complete. Further typing should result in recomputing
+ * this list.
+ */
+ bool isIncomplete() const { return typedValue<bool>(isIncompleteKey); }
+ void setIsIncomplete(bool isIncomplete) { insert(isIncompleteKey, isIncomplete); }
+
+ /// The completion items.
+ std::optional<QList<CompletionItem>> items() const { return array<CompletionItem>(itemsKey); }
+ void setItems(const QList<CompletionItem> &items) { insertArray(itemsKey, items); }
+ void clearItems() { remove(itemsKey); }
+
+ bool isValid() const override { return contains(isIncompleteKey); }
+};
+
+/// The result of a completion is CompletionItem[] | CompletionList | null
+class LANGUAGESERVERPROTOCOL_EXPORT CompletionResult
+ : public std::variant<QList<CompletionItem>, CompletionList, std::nullptr_t>
+{
+public:
+ using variant::variant;
+ explicit CompletionResult(const QJsonValue &value);
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT CompletionRequest : public Request<
+ CompletionResult, std::nullptr_t, CompletionParams>
+{
+public:
+ explicit CompletionRequest(const CompletionParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/completion";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT CompletionItemResolveRequest : public Request<
+ CompletionItem, std::nullptr_t, CompletionItem>
+{
+public:
+ explicit CompletionItemResolveRequest(const CompletionItem &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "completionItem/resolve";
+};
+
+} // namespace LanguageClient
diff --git a/src/shared/lsp/diagnostics.cpp b/src/shared/lsp/diagnostics.cpp
new file mode 100644
index 000000000..352b1572f
--- /dev/null
+++ b/src/shared/lsp/diagnostics.cpp
@@ -0,0 +1,13 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "diagnostics.h"
+
+namespace lsp {
+
+constexpr const char PublishDiagnosticsNotification::methodName[];
+
+PublishDiagnosticsNotification::PublishDiagnosticsNotification(const PublishDiagnosticsParams &params)
+ : Notification(methodName, params) { }
+
+} // namespace lsp
diff --git a/src/shared/lsp/diagnostics.h b/src/shared/lsp/diagnostics.h
new file mode 100644
index 000000000..ae479a23b
--- /dev/null
+++ b/src/shared/lsp/diagnostics.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "jsonrpcmessages.h"
+#include "languagefeatures.h"
+
+namespace lsp {
+
+class PublishDiagnosticsParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ DocumentUri uri() const { return DocumentUri::fromProtocol(typedValue<QString>(uriKey)); }
+ void setUri(const DocumentUri &uri) { insert(uriKey, uri); }
+
+ QList<Diagnostic> diagnostics() const { return array<Diagnostic>(diagnosticsKey); }
+ void setDiagnostics(const QList<Diagnostic> &diagnostics)
+ { insertArray(diagnosticsKey, diagnostics); }
+
+ std::optional<int> version() const { return optionalValue<int>(versionKey); }
+ void setVersion(int version) { insert(versionKey, version); }
+ void clearVersion() { remove(versionKey); }
+
+ bool isValid() const override { return contains(diagnosticsKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT PublishDiagnosticsNotification : public Notification<PublishDiagnosticsParams>
+{
+public:
+ explicit PublishDiagnosticsNotification(const PublishDiagnosticsParams &params);
+ using Notification::Notification;
+ constexpr static const char methodName[] = "textDocument/publishDiagnostics";
+};
+
+} // namespace LanguageClient
diff --git a/src/shared/lsp/filepath.h b/src/shared/lsp/filepath.h
new file mode 100644
index 000000000..736085828
--- /dev/null
+++ b/src/shared/lsp/filepath.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#pragma once
+
+#include <tools/hostosinfo.h>
+
+#include <QDir>
+#include <QFileInfo>
+#include <QString>
+
+namespace lsp::Utils {
+
+class FilePath : public QString
+{
+public:
+ FilePath() = default;
+ FilePath(const QString &s) : QString(s) {}
+
+ QString scheme() const { return {}; }
+ QString host() const { return {}; }
+ Qt::CaseSensitivity caseSensitivity() const {
+ return qbs::Internal::HostOsInfo::fileNameCaseSensitivity();
+ }
+ QString toString() const { return *this; }
+ QString path() const { return toString(); }
+
+ static FilePath fromUserInput(const QString &s) { return QDir::fromNativeSeparators(s); }
+ QString toUserOutput() const { return QDir::toNativeSeparators(*this); }
+};
+
+} // namespace lsp::Utils
diff --git a/src/shared/lsp/initializemessages.cpp b/src/shared/lsp/initializemessages.cpp
new file mode 100644
index 000000000..db0abcf49
--- /dev/null
+++ b/src/shared/lsp/initializemessages.cpp
@@ -0,0 +1,137 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "initializemessages.h"
+
+#include <QCoreApplication>
+
+namespace lsp {
+
+constexpr const char InitializeRequest::methodName[];
+constexpr const char InitializeNotification::methodName[];
+constexpr Trace::Values s_trace = Trace::off;
+
+Trace Trace::fromString(const QString &val)
+{
+ if (val == "messages")
+ return messages;
+ if (val == "verbose")
+ return verbose;
+ return off;
+}
+
+#define RETURN_CASE(name) case Trace::name: return QString(#name);
+QString Trace::toString() const
+{
+ switch (m_value) {
+ RETURN_CASE(off);
+ RETURN_CASE(messages);
+ RETURN_CASE(verbose);
+ }
+ return QString("off");
+}
+#undef RETURN_CASE
+
+std::optional<QList<MarkupKind>>
+TextDocumentClientCapabilities::CompletionCapabilities::CompletionItemCapbilities::
+documentationFormat() const
+{
+ return optionalArray<MarkupKind>(documentationFormatKey);
+}
+
+void
+TextDocumentClientCapabilities::CompletionCapabilities::CompletionItemCapbilities::
+setDocumentationFormat(const QList<MarkupKind> &documentationFormat)
+{
+ insertArray(documentationFormatKey, documentationFormat);
+}
+
+TextDocumentClientCapabilities::CompletionCapabilities::CompletionItemKindCapabilities::CompletionItemKindCapabilities()
+{
+ setValueSet({CompletionItemKind::Text, CompletionItemKind::Method, CompletionItemKind::Function,
+ CompletionItemKind::Constructor, CompletionItemKind::Field, CompletionItemKind::Variable,
+ CompletionItemKind::Class, CompletionItemKind::Interface, CompletionItemKind::Module,
+ CompletionItemKind::Property, CompletionItemKind::Unit, CompletionItemKind::Value,
+ CompletionItemKind::Enum, CompletionItemKind::Keyword, CompletionItemKind::Snippet,
+ CompletionItemKind::Color, CompletionItemKind::File, CompletionItemKind::Reference,
+ CompletionItemKind::Folder, CompletionItemKind::EnumMember, CompletionItemKind::Constant,
+ CompletionItemKind::Struct, CompletionItemKind::Event, CompletionItemKind::Operator,
+ CompletionItemKind::TypeParameter});
+}
+
+std::optional<QList<CompletionItemKind::Kind>>
+TextDocumentClientCapabilities::CompletionCapabilities::CompletionItemKindCapabilities::
+valueSet() const
+{
+ if (std::optional<QList<int>> array = optionalArray<int>(valueSetKey)) {
+ return std::make_optional(Utils::transform(*array, [](int value) {
+ return static_cast<CompletionItemKind::Kind>(value);
+ }));
+ }
+ return std::nullopt;
+}
+
+void
+TextDocumentClientCapabilities::CompletionCapabilities::CompletionItemKindCapabilities::
+setValueSet(const QList<CompletionItemKind::Kind> &valueSet)
+{
+ insert(valueSetKey, enumArrayToJsonArray<CompletionItemKind::Kind>(valueSet));
+}
+
+std::optional<QList<MarkupKind> > TextDocumentClientCapabilities::HoverCapabilities::contentFormat() const
+{
+ return optionalArray<MarkupKind>(contentFormatKey);
+}
+
+void TextDocumentClientCapabilities::HoverCapabilities::setContentFormat(const QList<MarkupKind> &contentFormat)
+{
+ insertArray(contentFormatKey, contentFormat);
+}
+
+std::optional<QList<MarkupKind>>
+TextDocumentClientCapabilities::SignatureHelpCapabilities::SignatureInformationCapabilities::
+documentationFormat() const
+{
+ return optionalArray<MarkupKind>(documentationFormatKey);
+}
+
+void
+TextDocumentClientCapabilities::SignatureHelpCapabilities::SignatureInformationCapabilities::
+setDocumentationFormat(const QList<MarkupKind> &documentationFormat)
+{
+ insertArray(documentationFormatKey, documentationFormat);
+}
+
+InitializeParams::InitializeParams()
+{
+ setProcessId(int(QCoreApplication::applicationPid()));
+ setRootUri(LanguageClientValue<DocumentUri>());
+ setCapabilities(ClientCapabilities());
+ setTrace(s_trace);
+}
+
+std::optional<QJsonObject> InitializeParams::initializationOptions() const
+{
+ const QJsonValue &optionsValue = value(initializationOptionsKey);
+ if (optionsValue.isObject())
+ return optionsValue.toObject();
+ return std::nullopt;
+}
+
+std::optional<Trace> InitializeParams::trace() const
+{
+ const QJsonValue &traceValue = value(traceKey);
+ if (traceValue.isUndefined())
+ return std::nullopt;
+ return std::make_optional(Trace(traceValue.toString()));
+}
+
+InitializeRequest::InitializeRequest(const InitializeParams &params)
+ : Request(methodName, params)
+{ }
+
+InitializeNotification::InitializeNotification(const InitializedParams &params)
+ : Notification(methodName, params)
+{ }
+
+} // namespace lsp
diff --git a/src/shared/lsp/initializemessages.h b/src/shared/lsp/initializemessages.h
new file mode 100644
index 000000000..159d62ded
--- /dev/null
+++ b/src/shared/lsp/initializemessages.h
@@ -0,0 +1,187 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "clientcapabilities.h"
+#include "jsonrpcmessages.h"
+#include "lsptypes.h"
+#include "servercapabilities.h"
+
+namespace lsp {
+
+class LANGUAGESERVERPROTOCOL_EXPORT Trace
+{
+public:
+ enum Values
+ {
+ off,
+ messages,
+ verbose
+ };
+
+ Trace() = default;
+ Trace(Values val) : m_value(val) {}
+ Trace(QString val) : Trace(fromString(val)) {}
+
+ static Trace fromString(const QString& val);
+ QString toString() const;
+
+private:
+ Values m_value = off;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ClientInfo : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ QString name() const { return typedValue<QString>(nameKey); }
+ void setName(const QString &name) { insert(nameKey, name); }
+
+ std::optional<QString> version() const { return optionalValue<QString>(versionKey); }
+ void setVersion(const QString &version) { insert(versionKey, version); }
+ void clearVersion() { remove(versionKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT InitializeParams : public JsonObject
+{
+public:
+ InitializeParams();
+ using JsonObject::JsonObject;
+
+ /*
+ * The process Id of the parent process that started
+ * the server. Is null if the process has not been started by another process.
+ * If the parent process is not alive then the server should exit (see exit notification)
+ * its process.
+ */
+ LanguageClientValue<int> processId() const { return clientValue<int>(processIdKey); }
+ void setProcessId(const LanguageClientValue<int> &id) { insert(processIdKey, id); }
+
+ /*
+ * The rootPath of the workspace. Is null
+ * if no folder is open.
+ *
+ * @deprecated in favor of rootUri.
+ */
+ std::optional<LanguageClientValue<QString>> rootPath() const
+ { return optionalClientValue<QString>(rootPathKey); }
+ void setRootPath(const LanguageClientValue<QString> &path)
+ { insert(rootPathKey, path); }
+ void clearRootPath() { remove(rootPathKey); }
+
+ /*
+ * The rootUri of the workspace. Is null if no
+ * folder is open. If both `rootPath` and `rootUri` are set
+ * `rootUri` wins.
+ */
+ LanguageClientValue<DocumentUri> rootUri() const
+ { return clientValue<QString>(rootUriKey).transform<DocumentUri>(); }
+ void setRootUri(const LanguageClientValue<DocumentUri> &uri)
+ { insert(rootUriKey, uri); }
+
+ // User provided initialization options.
+ std::optional<QJsonObject> initializationOptions() const;
+ void setInitializationOptions(const QJsonObject &options)
+ { insert(initializationOptionsKey, options); }
+ void clearInitializationOptions() { remove(initializationOptionsKey); }
+
+ // The capabilities provided by the client (editor or tool)
+ ClientCapabilities capabilities() const { return typedValue<ClientCapabilities>(capabilitiesKey); }
+ void setCapabilities(const ClientCapabilities &capabilities)
+ { insert(capabilitiesKey, capabilities); }
+
+ // The initial trace setting. If omitted trace is disabled ('off').
+ std::optional<Trace> trace() const;
+ void setTrace(Trace trace) { insert(traceKey, trace.toString()); }
+ void clearTrace() { remove(traceKey); }
+
+ /*
+ * The workspace folders configured in the client when the server starts.
+ * This property is only available if the client supports workspace folders.
+ * It can be `null` if the client supports workspace folders but none are
+ * configured.
+ *
+ * Since 3.6.0
+ */
+ std::optional<LanguageClientArray<WorkSpaceFolder>> workspaceFolders() const
+ { return optionalClientArray<WorkSpaceFolder>(workspaceFoldersKey); }
+ void setWorkSpaceFolders(const LanguageClientArray<WorkSpaceFolder> &folders)
+ { insert(workspaceFoldersKey, folders.toJson()); }
+ void clearWorkSpaceFolders() { remove(workspaceFoldersKey); }
+
+ std::optional<ClientInfo> clientInfo() const { return optionalValue<ClientInfo>(clientInfoKey); }
+ void setClientInfo(const ClientInfo &clientInfo) { insert(clientInfoKey, clientInfo); }
+ void clearClientInfo() { remove(clientInfoKey); }
+
+ bool isValid() const override
+ { return contains(processIdKey) && contains(rootUriKey) && contains(capabilitiesKey); }
+};
+
+using InitializedParams = JsonObject;
+
+class LANGUAGESERVERPROTOCOL_EXPORT InitializeNotification : public Notification<InitializedParams>
+{
+public:
+ explicit InitializeNotification(const InitializedParams &params);
+ using Notification::Notification;
+ constexpr static const char methodName[] = "initialized";
+
+ bool parametersAreValid(QString * /*errorMessage*/) const final { return true; }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ServerInfo : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ QString name() const { return typedValue<QString>(nameKey); }
+ std::optional<QString> version() const { return optionalValue<QString>(versionKey); }
+
+ bool isValid() const override { return contains(nameKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT InitializeResult : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ ServerCapabilities capabilities() const
+ { return typedValue<ServerCapabilities>(capabilitiesKey); }
+ void setCapabilities(const ServerCapabilities &capabilities)
+ { insert(capabilitiesKey, capabilities); }
+
+ std::optional<ServerInfo> serverInfo() const
+ { return optionalValue<ServerInfo>(serverInfoKey); }
+
+ bool isValid() const override { return contains(capabilitiesKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT InitializeError : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ /*
+ * Indicates whether the client execute the following retry logic:
+ * (1) show the message provided by the ResponseError to the user
+ * (2) user selects retry or cancel
+ * (3) if user selected retry the initialize method is sent again.
+ */
+ bool retry() const { return typedValue<bool>(retryKey); }
+ void setRetry(const bool &retry) { insert(retryKey, retry); }
+
+ bool isValid() const override { return contains(retryKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT InitializeRequest : public Request<
+ InitializeResult, InitializeError, InitializeParams>
+{
+public:
+ explicit InitializeRequest(const InitializeParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "initialize";
+};
+
+} // namespace LanguageClient
diff --git a/src/shared/lsp/jsonkeys.h b/src/shared/lsp/jsonkeys.h
new file mode 100644
index 000000000..5e5491caa
--- /dev/null
+++ b/src/shared/lsp/jsonkeys.h
@@ -0,0 +1,231 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+namespace lsp {
+
+constexpr char actionsKey[] = "actions";
+constexpr char activeParameterKey[] = "activeParameter";
+constexpr char activeParameterSupportKey[] = "activeParameterSupport";
+constexpr char activeSignatureKey[] = "activeSignature";
+constexpr char addedKey[] = "added";
+constexpr char additionalTextEditsKey[] = "additionalTextEdits";
+constexpr char alphaKey[] = "alpha";
+constexpr char appliedKey[] = "applied";
+constexpr char applyEditKey[] = "applyEdit";
+constexpr char argumentsKey[] = "arguments";
+constexpr char blueKey[] = "blue";
+constexpr char callHierarchyKey[] = "callHierarchy";
+constexpr char callHierarchyProviderKey[] = "callHierarchyProvider";
+constexpr char cancellableKey[] = "cancellable";
+constexpr char capabilitiesKey[] = "capabilities";
+constexpr char chKey[] = "ch";
+constexpr char changeKey[] = "change";
+constexpr char changeNotificationsKey[] = "changeNotifications";
+constexpr char changesKey[] = "changes";
+constexpr char characterKey[] = "character";
+constexpr char childrenKey[] = "children";
+constexpr char clientInfoKey[] = "clientInfo";
+constexpr char codeActionKey[] = "codeAction";
+constexpr char codeActionKindKey[] = "codeActionKind";
+constexpr char codeActionKindsKey[] = "codeActionKinds";
+constexpr char codeActionLiteralSupportKey[] = "codeActionLiteralSupport";
+constexpr char codeActionProviderKey[] = "codeActionProvider";
+constexpr char codeKey[] = "code";
+constexpr char codeLensKey[] = "codeLens";
+constexpr char codeLensProviderKey[] = "codeLensProvider";
+constexpr char colorInfoKey[] = "colorInfo";
+constexpr char colorKey[] = "color";
+constexpr char colorProviderKey[] = "colorProvider";
+constexpr char commandKey[] = "command";
+constexpr char commandsKey[] = "commands";
+constexpr char commitCharacterSupportKey[] = "commitCharacterSupport";
+constexpr char commitCharactersKey[] = "commitCharacters";
+constexpr char completionItemKey[] = "completionItem";
+constexpr char completionItemKindKey[] = "completionItemKind";
+constexpr char completionKey[] = "completion";
+constexpr char completionProviderKey[] = "completionProvider";
+constexpr char configurationKey[] = "configuration";
+constexpr char containerNameKey[] = "containerName";
+constexpr char contentChangesKey[] = "contentChanges";
+constexpr char contentFormatKey[] = "contentFormat";
+constexpr char contentKey[] = "value";
+constexpr char contentsKey[] = "contents";
+constexpr char contextKey[] = "context";
+constexpr char contextSupportKey[] = "contextSupport";
+constexpr char dataKey[] = "data";
+constexpr char definitionKey[] = "definition";
+constexpr char definitionProviderKey[] = "definitionProvider";
+constexpr char deleteCountKey[] = "deleteCount";
+constexpr char deltaKey[] = "delta";
+constexpr char deprecatedKey[] = "deprecated";
+constexpr char detailKey[] = "detail";
+constexpr char diagnosticsKey[] = "diagnostics";
+constexpr char didChangeConfigurationKey[] = "didChangeConfiguration";
+constexpr char didChangeWatchedFilesKey[] = "didChangeWatchedFiles";
+constexpr char didSaveKey[] = "didSave";
+constexpr char documentChangesKey[] = "documentChanges";
+constexpr char documentFormattingProviderKey[] = "documentFormattingProvider";
+constexpr char documentHighlightKey[] = "documentHighlight";
+constexpr char documentHighlightProviderKey[] = "documentHighlightProvider";
+constexpr char documentLinkKey[] = "documentLink";
+constexpr char documentLinkProviderKey[] = "documentLinkProvider";
+constexpr char documentRangeFormattingProviderKey[] = "documentRangeFormattingProvider";
+constexpr char documentSelectorKey[] = "documentSelector";
+constexpr char documentSymbolKey[] = "documentSymbol";
+constexpr char documentSymbolProviderKey[] = "documentSymbolProvider";
+constexpr char documentationFormatKey[] = "documentationFormat";
+constexpr char documentationKey[] = "documentation";
+constexpr char dynamicRegistrationKey[] = "dynamicRegistration";
+constexpr char editKey[] = "edit";
+constexpr char editsKey[] = "edits";
+constexpr char endKey[] = "end";
+constexpr char errorKey[] = "error";
+constexpr char eventKey[] = "event";
+constexpr char executeCommandKey[] = "executeCommand";
+constexpr char executeCommandProviderKey[] = "executeCommandProvider";
+constexpr char experimentalKey[] = "experimental";
+constexpr char filterTextKey[] = "filterText";
+constexpr char firstTriggerCharacterKey[] = "firstTriggerCharacter";
+constexpr char formatsKey[] = "formats";
+constexpr char formattingKey[] = "formatting";
+constexpr char fromKey[] = "from";
+constexpr char fromRangesKey[] = "fromRanges";
+constexpr char fullKey[] = "full";
+constexpr char greenKey[] = "green";
+constexpr char hierarchicalDocumentSymbolSupportKey[] = "hierarchicalDocumentSymbolSupport";
+constexpr char hoverKey[] = "hover";
+constexpr char hoverProviderKey[] = "hoverProvider";
+constexpr char idKey[] = "id";
+constexpr char ignoreIfExistsKey[] = "ignoreIfExists";
+constexpr char ignoreIfNotExistsKey[] = "ignoreIfNotExists";
+constexpr char implementationKey[] = "implementation";
+constexpr char implementationProviderKey[] = "implementationProvider";
+constexpr char includeDeclarationKey[] = "includeDeclaration";
+constexpr char includeTextKey[] = "includeText";
+constexpr char initializationOptionsKey[] = "initializationOptions";
+constexpr char insertFinalNewlineKey[] = "insertFinalNewline";
+constexpr char insertSpaceKey[] = "insertSpace";
+constexpr char insertTextFormatKey[] = "insertTextFormat";
+constexpr char insertTextKey[] = "insertText";
+constexpr char isIncompleteKey[] = "isIncomplete";
+constexpr char itemKey[] = "item";
+constexpr char itemsKey[] = "items";
+constexpr char jsonRpcVersionKey[] = "jsonrpc";
+constexpr char kindKey[] = "kind";
+constexpr char labelKey[] = "label";
+constexpr char languageIdKey[] = "languageId";
+constexpr char languageKey[] = "language";
+constexpr char legendKey[] = "legend";
+constexpr char limitKey[] = "limit";
+constexpr char lineKey[] = "line";
+constexpr char linesKey[] = "lines";
+constexpr char locationKey[] = "location";
+constexpr char messageKey[] = "message";
+constexpr char methodKey[] = "method";
+constexpr char moreTriggerCharacterKey[] = "moreTriggerCharacter";
+constexpr char multiLineTokenSupportKey[] = "multiLineTokenSupport";
+constexpr char nameKey[] = "name";
+constexpr char newNameKey[] = "newName";
+constexpr char newTextKey[] = "newText";
+constexpr char newUriKey[] = "newUri";
+constexpr char oldUriKey[] = "oldUri";
+constexpr char onTypeFormattingKey[] = "onTypeFormatting";
+constexpr char onlyKey[] = "only";
+constexpr char openCloseKey[] = "openClose";
+constexpr char optionsKey[] = "options";
+constexpr char overlappingTokenSupportKey[] = "overlappingTokenSupport";
+constexpr char overwriteKey[] = "overwrite";
+constexpr char parametersKey[] = "parameters";
+constexpr char paramsKey[] = "params";
+constexpr char patternKey[] = "pattern";
+constexpr char percentageKey[] = "percentage";
+constexpr char placeHolderKey[] = "placeHolder";
+constexpr char positionKey[] = "position";
+constexpr char prepareProviderKey[] = "prepareProvider";
+constexpr char prepareSupportKey[] = "prepareSupport";
+constexpr char previousResultIdKey[] = "previousResultId";
+constexpr char processIdKey[] = "processId";
+constexpr char queryKey[] = "query";
+constexpr char rangeFormattingKey[] = "rangeFormatting";
+constexpr char rangeKey[] = "range";
+constexpr char rangeLengthKey[] = "rangeLength";
+constexpr char reasonKey[] = "reason";
+constexpr char recursiveKey[] = "recursive";
+constexpr char redKey[] = "red";
+constexpr char referencesKey[] = "references";
+constexpr char referencesProviderKey[] = "referencesProvider";
+constexpr char refreshSupportKey[] = "refreshSupport";
+constexpr char registerOptionsKey[] = "registerOptions";
+constexpr char registrationsKey[] = "registrations";
+constexpr char removedKey[] = "removed";
+constexpr char renameKey[] = "rename";
+constexpr char renameProviderKey[] = "renameProvider";
+constexpr char requestsKey[] = "requests";
+constexpr char resolveProviderKey[] = "resolveProvider";
+constexpr char resourceOperationsKey[] = "resourceOperations";
+constexpr char resultIdKey[] = "resultId";
+constexpr char resultKey[] = "result";
+constexpr char retryKey[] = "retry";
+constexpr char rootPathKey[] = "rootPath";
+constexpr char rootUriKey[] = "rootUri";
+constexpr char saveKey[] = "save";
+constexpr char schemeKey[] = "scheme";
+constexpr char scopeUriKey[] = "scopeUri";
+constexpr char sectionKey[] = "section";
+constexpr char selectionRangeKey[] = "selectionRange";
+constexpr char semanticTokensKey[] = "semanticTokens";
+constexpr char semanticTokensProviderKey[] = "semanticTokensProvider";
+constexpr char serverInfoKey[] = "serverInfo";
+constexpr char settingsKey[] = "settings";
+constexpr char severityKey[] = "severity";
+constexpr char signatureHelpKey[] = "signatureHelp";
+constexpr char signatureHelpProviderKey[] = "signatureHelpProvider";
+constexpr char signatureInformationKey[] = "signatureInformation";
+constexpr char signaturesKey[] = "signatures";
+constexpr char snippetSupportKey[] = "snippetSupport";
+constexpr char sortTextKey[] = "sortText";
+constexpr char sourceKey[] = "source";
+constexpr char startKey[] = "start";
+constexpr char supportedKey[] = "supported";
+constexpr char symbolKey[] = "symbol";
+constexpr char symbolKindKey[] = "symbolKind";
+constexpr char syncKindKey[] = "syncKind";
+constexpr char synchronizationKey[] = "synchronization";
+constexpr char tabSizeKey[] = "tabSize";
+constexpr char tagsKey[] = "tags";
+constexpr char targetKey[] = "target";
+constexpr char textDocumentKey[] = "textDocument";
+constexpr char textDocumentSyncKey[] = "textDocumentSync";
+constexpr char textEditKey[] = "textEdit";
+constexpr char textKey[] = "text";
+constexpr char titleKey[] = "title";
+constexpr char toKey[] = "to";
+constexpr char tokenKey[] = "token";
+constexpr char tokenModifiersKey[] = "tokenModifiers";
+constexpr char tokenTypesKey[] = "tokenTypes";
+constexpr char traceKey[] = "trace";
+constexpr char triggerCharacterKey[] = "triggerCharacter";
+constexpr char triggerCharactersKey[] = "triggerCharacters";
+constexpr char triggerKindKey[] = "triggerKind";
+constexpr char trimFinalNewlinesKey[] = "trimFinalNewlines";
+constexpr char trimTrailingWhitespaceKey[] = "trimTrailingWhitespace";
+constexpr char typeDefinitionKey[] = "typeDefinition";
+constexpr char typeDefinitionProviderKey[] = "typeDefinitionProvider";
+constexpr char typeKey[] = "type";
+constexpr char unregistrationsKey[] = "unregistrations";
+constexpr char uriKey[] = "uri";
+constexpr char valueKey[] = "value";
+constexpr char valueSetKey[] = "valueSet";
+constexpr char versionKey[] = "version";
+constexpr char willSaveKey[] = "willSave";
+constexpr char willSaveWaitUntilKey[] = "willSaveWaitUntil";
+constexpr char windowKey[] = "window";
+constexpr char workDoneProgressKey[] = "workDoneProgress";
+constexpr char workspaceEditKey[] = "workspaceEdit";
+constexpr char workspaceFoldersKey[] = "workspaceFolders";
+constexpr char workspaceKey[] = "workspace";
+constexpr char workspaceSymbolProviderKey[] = "workspaceSymbolProvider";
+
+} // namespace lsp
diff --git a/src/shared/lsp/jsonobject.cpp b/src/shared/lsp/jsonobject.cpp
new file mode 100644
index 000000000..887d79a5e
--- /dev/null
+++ b/src/shared/lsp/jsonobject.cpp
@@ -0,0 +1,28 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "jsonobject.h"
+
+#include <QCoreApplication>
+
+namespace lsp {
+
+JsonObject &JsonObject::operator=(const JsonObject &other) = default;
+
+JsonObject &JsonObject::operator=(JsonObject &&other)
+{
+ m_jsonObject.swap(other.m_jsonObject);
+ return *this;
+}
+
+QJsonObject::iterator JsonObject::insert(const std::string_view key, const JsonObject &object)
+{
+ return m_jsonObject.insert(QLatin1String(key.data()), object.m_jsonObject);
+}
+
+QJsonObject::iterator JsonObject::insert(const std::string_view key, const QJsonValue &value)
+{
+ return m_jsonObject.insert(QLatin1String(key.data()), value);
+}
+
+} // namespace lsp
diff --git a/src/shared/lsp/jsonobject.h b/src/shared/lsp/jsonobject.h
new file mode 100644
index 000000000..29811839f
--- /dev/null
+++ b/src/shared/lsp/jsonobject.h
@@ -0,0 +1,181 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "algorithm.h"
+#include "languageserverprotocol_global.h"
+#include "lsputils.h"
+
+#include <QCoreApplication>
+#include <QDebug>
+#include <QJsonObject>
+
+#include <optional>
+
+namespace lsp {
+
+class LANGUAGESERVERPROTOCOL_EXPORT JsonObject
+{
+public:
+ using iterator = QJsonObject::iterator;
+ using const_iterator = QJsonObject::const_iterator;
+
+ JsonObject() = default;
+
+ explicit JsonObject(const QJsonObject &object) : m_jsonObject(object) { }
+ explicit JsonObject(QJsonObject &&object) : m_jsonObject(std::move(object)) { }
+
+ JsonObject(const JsonObject &object) : m_jsonObject(object.m_jsonObject) { }
+ JsonObject(JsonObject &&object) : m_jsonObject(std::move(object.m_jsonObject)) { }
+
+ explicit JsonObject(const QJsonValue &value) : m_jsonObject(value.toObject()) { }
+
+ virtual ~JsonObject() = default;
+
+ JsonObject &operator=(const JsonObject &other);
+ JsonObject &operator=(JsonObject &&other);
+
+ bool operator==(const JsonObject &other) const { return m_jsonObject == other.m_jsonObject; }
+
+ operator const QJsonObject&() const { return m_jsonObject; }
+
+ virtual bool isValid() const { return true; }
+
+ iterator end() { return m_jsonObject.end(); }
+ const_iterator end() const { return m_jsonObject.end(); }
+
+ iterator insert(const std::string_view key, const JsonObject &value);
+ iterator insert(const std::string_view key, const QJsonValue &value);
+
+protected:
+
+ template <typename T, typename V>
+ iterator insertVariant(const std::string_view key, const V &variant);
+ template <typename T1, typename T2, typename... Args, typename V>
+ iterator insertVariant(const std::string_view key, const V &variant);
+
+ // QJSonObject redirections
+ QJsonValue value(const std::string_view key) const { return m_jsonObject.value(QLatin1String(key.data())); }
+ bool contains(const std::string_view key) const { return m_jsonObject.contains(QLatin1String(key.data())); }
+ iterator find(const std::string_view key) { return m_jsonObject.find(QLatin1String(key.data())); }
+ const_iterator find(const std::string_view key) const { return m_jsonObject.find(QLatin1String(key.data())); }
+ void remove(const std::string_view key) { m_jsonObject.remove(QLatin1String(key.data())); }
+ QStringList keys() const { return m_jsonObject.keys(); }
+
+ // convenience value access
+ template<typename T>
+ T typedValue(const std::string_view key) const;
+ template<typename T>
+ std::optional<T> optionalValue(const std::string_view key) const;
+ template<typename T>
+ LanguageClientValue<T> clientValue(const std::string_view key) const;
+ template<typename T>
+ std::optional<LanguageClientValue<T>> optionalClientValue(const std::string_view key) const;
+ template<typename T>
+ QList<T> array(const std::string_view key) const;
+ template<typename T>
+ std::optional<QList<T>> optionalArray(const std::string_view key) const;
+ template<typename T>
+ LanguageClientArray<T> clientArray(const std::string_view key) const;
+ template<typename T>
+ std::optional<LanguageClientArray<T>> optionalClientArray(const std::string_view key) const;
+ template<typename T>
+ void insertArray(const std::string_view key, const QList<T> &array);
+ template<typename>
+ void insertArray(const std::string_view key, const QList<JsonObject> &array);
+
+private:
+ QJsonObject m_jsonObject;
+};
+
+template<typename T, typename V>
+JsonObject::iterator JsonObject::insertVariant(const std::string_view key, const V &variant)
+{
+ return std::holds_alternative<T>(variant) ? insert(key, std::get<T>(variant)) : end();
+}
+
+template<typename T1, typename T2, typename... Args, typename V>
+JsonObject::iterator JsonObject::insertVariant(const std::string_view key, const V &variant)
+{
+ auto result = insertVariant<T1>(key, variant);
+ return result != end() ? result : insertVariant<T2, Args...>(key, variant);
+}
+
+template<typename T>
+T JsonObject::typedValue(const std::string_view key) const
+{
+ return fromJsonValue<T>(value(key));
+}
+
+template<typename T>
+std::optional<T> JsonObject::optionalValue(const std::string_view key) const
+{
+ const QJsonValue &val = value(key);
+ return val.isUndefined() ? std::nullopt : std::make_optional(fromJsonValue<T>(val));
+}
+
+template<typename T>
+LanguageClientValue<T> JsonObject::clientValue(const std::string_view key) const
+{
+ return LanguageClientValue<T>(value(key));
+}
+
+template<typename T>
+std::optional<LanguageClientValue<T>> JsonObject::optionalClientValue(const std::string_view key) const
+{
+ return contains(key) ? std::make_optional(clientValue<T>(key)) : std::nullopt;
+}
+
+template<typename T>
+QList<T> JsonObject::array(const std::string_view key) const
+{
+ if (const std::optional<QList<T>> &array = optionalArray<T>(key))
+ return *array;
+ qCDebug(conversionLog) << QString("Expected array under %1 in:")
+ .arg(QLatin1String(key.data())) << *this;
+ return {};
+}
+
+template<typename T>
+std::optional<QList<T>> JsonObject::optionalArray(const std::string_view key) const
+{
+ const QJsonValue &jsonValue = value(key);
+ if (jsonValue.isUndefined())
+ return std::nullopt;
+ return Utils::transform<QList<T>>(jsonValue.toArray(), &fromJsonValue<T>);
+}
+
+template<typename T>
+LanguageClientArray<T> JsonObject::clientArray(const std::string_view key) const
+{
+ return LanguageClientArray<T>(value(key));
+}
+
+template<typename T>
+std::optional<LanguageClientArray<T>> JsonObject::optionalClientArray(const std::string_view key) const
+{
+ const QJsonValue &val = value(key);
+ return !val.isUndefined() ? std::make_optional(LanguageClientArray<T>(value(key)))
+ : std::nullopt;
+}
+
+template<typename T>
+void JsonObject::insertArray(const std::string_view key, const QList<T> &array)
+{
+ QJsonArray jsonArray;
+ for (const T &item : array)
+ jsonArray.append(QJsonValue(item));
+ insert(key, jsonArray);
+}
+
+template<typename >
+void JsonObject::insertArray(const std::string_view key, const QList<JsonObject> &array)
+{
+ QJsonArray jsonArray;
+ for (const JsonObject &item : array)
+ jsonArray.append(item.m_jsonObject);
+ insert(key, jsonArray);
+}
+
+} // namespace lsp
diff --git a/src/shared/lsp/jsonrpcmessages.cpp b/src/shared/lsp/jsonrpcmessages.cpp
new file mode 100644
index 000000000..dbe354bc4
--- /dev/null
+++ b/src/shared/lsp/jsonrpcmessages.cpp
@@ -0,0 +1,107 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "jsonrpcmessages.h"
+
+#include "initializemessages.h"
+#include "languageserverprotocoltr.h"
+#include "lsputils.h"
+
+#include <QCoreApplication>
+#include <QObject>
+#include <QJsonDocument>
+#include <QTextCodec>
+
+namespace lsp {
+Q_LOGGING_CATEGORY(timingLog, "qtc.languageserverprotocol.timing", QtWarningMsg)
+
+constexpr const char CancelRequest::methodName[];
+
+QByteArray JsonRpcMessage::toRawData() const
+{
+ return QJsonDocument(m_jsonObject).toJson(QJsonDocument::Compact);
+}
+
+bool JsonRpcMessage::isValid(QString *errorMessage) const
+{
+ if (!m_parseError.isEmpty()) {
+ if (errorMessage)
+ *errorMessage = m_parseError;
+ return false;
+ }
+ return m_jsonObject[jsonRpcVersionKey] == "2.0";
+}
+
+const QJsonObject &JsonRpcMessage::toJsonObject() const
+{
+ return m_jsonObject;
+}
+
+JsonRpcMessage::JsonRpcMessage()
+{
+ // The language server protocol always uses “2.0” as the jsonrpc version
+ m_jsonObject[jsonRpcVersionKey] = "2.0";
+}
+
+constexpr int utf8mib = 106;
+
+static QString docType(const QJsonDocument &doc)
+{
+ if (doc.isArray())
+ return QString("array");
+ if (doc.isEmpty())
+ return QString("empty");
+ if (doc.isNull())
+ return QString("null");
+ if (doc.isObject())
+ return QString("object");
+ return {};
+}
+
+JsonRpcMessage::JsonRpcMessage(const BaseMessage &message)
+{
+ if (message.content.isEmpty())
+ return;
+ QByteArray content;
+ if (message.codec && message.codec->mibEnum() != utf8mib) {
+ QTextCodec *utf8 = QTextCodec::codecForMib(utf8mib);
+ if (utf8)
+ content = utf8->fromUnicode(message.codec->toUnicode(message.content));
+ }
+ if (content.isEmpty())
+ content = message.content;
+ QJsonParseError error = {0, QJsonParseError::NoError};
+ const QJsonDocument doc = QJsonDocument::fromJson(content, &error);
+ if (doc.isObject())
+ m_jsonObject = doc.object();
+ else if (doc.isNull())
+ m_parseError = Tr::tr("Could not parse JSON message: \"%1\".").arg(error.errorString());
+ else
+ m_parseError =
+ Tr::tr("Expected a JSON object, but got a JSON \"%1\" value.").arg(docType(doc));
+}
+
+JsonRpcMessage::JsonRpcMessage(const QJsonObject &jsonObject)
+ : m_jsonObject(jsonObject)
+{ }
+
+JsonRpcMessage::JsonRpcMessage(QJsonObject &&jsonObject)
+ : m_jsonObject(std::move(jsonObject))
+{ }
+
+QByteArray JsonRpcMessage::jsonRpcMimeType()
+{
+ return "application/vscode-jsonrpc";
+}
+
+CancelRequest::CancelRequest(const CancelParameter &params)
+ : Notification(methodName, params)
+{ }
+
+void logElapsedTime(const QString &method, const QElapsedTimer &t)
+{
+ qCDebug(timingLog) << "received server reply to" << method
+ << "after" << t.elapsed() << "ms";
+}
+
+} // namespace lsp
diff --git a/src/shared/lsp/jsonrpcmessages.h b/src/shared/lsp/jsonrpcmessages.h
new file mode 100644
index 000000000..a523dd5e1
--- /dev/null
+++ b/src/shared/lsp/jsonrpcmessages.h
@@ -0,0 +1,415 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "basemessage.h"
+#include "jsonkeys.h"
+#include "lsptypes.h"
+
+#include <QDebug>
+#include <QElapsedTimer>
+#include <QHash>
+#include <QJsonObject>
+#include <QJsonValue>
+#include <QCoreApplication>
+#include <QUuid>
+
+#include <optional>
+#include <variant>
+
+namespace lsp {
+
+class JsonRpcMessage;
+
+class LANGUAGESERVERPROTOCOL_EXPORT MessageId : public std::variant<int, QString>
+{
+public:
+ MessageId() : variant(QString()) {}
+ explicit MessageId(int id) : variant(id) {}
+ explicit MessageId(const QString &id) : variant(id) {}
+ explicit MessageId(const QJsonValue &value)
+ {
+ if (value.isDouble())
+ emplace<int>(value.toInt());
+ else
+ emplace<QString>(value.toString());
+ }
+
+ operator QJsonValue() const
+ {
+ if (auto id = std::get_if<int>(this))
+ return *id;
+ if (auto id = std::get_if<QString>(this))
+ return *id;
+ return QJsonValue();
+ }
+
+ bool isValid() const
+ {
+ if (std::holds_alternative<int>(*this))
+ return true;
+ const QString *id = std::get_if<QString>(this);
+ QBS_ASSERT(id, return false);
+ return !id->isEmpty();
+ }
+
+ QString toString() const
+ {
+ if (auto id = std::get_if<QString>(this))
+ return *id;
+ if (auto id = std::get_if<int>(this))
+ return QString::number(*id);
+ return {};
+ }
+
+private:
+ friend size_t qHash(const MessageId &id)
+ {
+ if (std::holds_alternative<int>(id))
+ return QT_PREPEND_NAMESPACE(qHash(std::get<int>(id)));
+ if (std::holds_alternative<QString>(id))
+ return QT_PREPEND_NAMESPACE(qHash(std::get<QString>(id)));
+ return QT_PREPEND_NAMESPACE(qHash(0));
+ }
+
+ friend QDebug operator<<(QDebug stream, const MessageId &id)
+ {
+ if (std::holds_alternative<int>(id))
+ stream << std::get<int>(id);
+ else
+ stream << std::get<QString>(id);
+ return stream;
+ }
+};
+
+struct ResponseHandler
+{
+ MessageId id;
+ using Callback = std::function<void(const JsonRpcMessage &)>;
+ Callback callback;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT JsonRpcMessage
+{
+public:
+ JsonRpcMessage();
+ explicit JsonRpcMessage(const BaseMessage &message);
+ explicit JsonRpcMessage(const QJsonObject &jsonObject);
+ explicit JsonRpcMessage(QJsonObject &&jsonObject);
+
+ virtual ~JsonRpcMessage() = default;
+
+ static QByteArray jsonRpcMimeType();
+
+ QByteArray toRawData() const;
+ virtual bool isValid(QString *errorMessage) const;
+
+ const QJsonObject &toJsonObject() const;
+
+ const QString parseError() { return m_parseError; }
+
+ virtual std::optional<ResponseHandler> responseHandler() const { return std::nullopt; }
+
+ BaseMessage toBaseMessage() const
+ { return BaseMessage(jsonRpcMimeType(), toRawData()); }
+
+protected:
+ QJsonObject m_jsonObject;
+
+private:
+ QString m_parseError;
+};
+
+template <typename Params>
+class Notification : public JsonRpcMessage
+{
+public:
+ Notification(const QString &methodName, const Params &params)
+ {
+ setMethod(methodName);
+ setParams(params);
+ }
+
+ explicit Notification(const QJsonObject &jsonObject) : JsonRpcMessage(jsonObject) {}
+ explicit Notification(QJsonObject &&jsonObject) : JsonRpcMessage(std::move(jsonObject)) {}
+
+ QString method() const
+ { return fromJsonValue<QString>(m_jsonObject.value(methodKey)); }
+ void setMethod(const QString &method)
+ { m_jsonObject.insert(methodKey, method); }
+
+ using Parameters = Params;
+ std::optional<Params> params() const
+ {
+ const QJsonValue &params = m_jsonObject.value(paramsKey);
+ return params.isUndefined() ? std::nullopt : std::make_optional(Params(params));
+ }
+ void setParams(const Params &params)
+ { m_jsonObject.insert(paramsKey, QJsonValue(params)); }
+ void clearParams() { m_jsonObject.remove(paramsKey); }
+
+ bool isValid(QString *errorMessage) const override
+ {
+ return JsonRpcMessage::isValid(errorMessage)
+ && m_jsonObject.value(methodKey).isString()
+ && parametersAreValid(errorMessage);
+ }
+
+ virtual bool parametersAreValid(QString *errorMessage) const
+ {
+ if (auto parameter = params())
+ return parameter->isValid();
+ if (errorMessage)
+ *errorMessage = QCoreApplication::translate("QtC::LanguageServerProtocol",
+ "No parameters in \"%1\".").arg(method());
+ return false;
+ }
+};
+
+template <>
+class Notification<std::nullptr_t> : public JsonRpcMessage
+{
+public:
+ Notification() : Notification(QString()) {}
+ explicit Notification(const QString &methodName, const std::nullptr_t &/*params*/ = nullptr)
+ {
+ setMethod(methodName);
+ setParams(nullptr);
+ }
+ using JsonRpcMessage::JsonRpcMessage;
+
+ QString method() const
+ { return fromJsonValue<QString>(m_jsonObject.value(methodKey)); }
+ void setMethod(const QString &method)
+ { m_jsonObject.insert(methodKey, method); }
+
+ std::optional<std::nullptr_t> params() const
+ { return nullptr; }
+ void setParams(const std::nullptr_t &/*params*/)
+ { m_jsonObject.insert(paramsKey, QJsonValue::Null); }
+ void clearParams() { m_jsonObject.remove(paramsKey); }
+
+ bool isValid(QString *errorMessage) const override
+ {
+ return JsonRpcMessage::isValid(errorMessage)
+ && m_jsonObject.value(methodKey).isString()
+ && parametersAreValid(errorMessage);
+ }
+
+ virtual bool parametersAreValid(QString * /*errorMessage*/) const
+ { return true; }
+};
+
+template <typename Error>
+class ResponseError : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ int code() const { return typedValue<int>(codeKey); }
+ void setCode(int code) { insert(codeKey, code); }
+
+ QString message() const { return typedValue<QString>(messageKey); }
+ void setMessage(const QString &message) { insert(messageKey, message); }
+
+ std::optional<Error> data() const { return optionalValue<Error>(dataKey); }
+ void setData(const Error &data) { insert(dataKey, data); }
+ void clearData() { remove(dataKey); }
+
+ bool isValid() const override { return contains(codeKey) && contains(messageKey); }
+
+ QString toString() const { return errorCodesToString(code()) + ": " + message(); }
+
+ // predefined error codes
+ enum ErrorCodes {
+ // Defined by JSON RPC
+ ParseError = -32700,
+ InvalidRequest = -32600,
+ MethodNotFound = -32601,
+ InvalidParams = -32602,
+ InternalError = -32603,
+ serverErrorStart = -32099,
+ serverErrorEnd = -32000,
+ ServerNotInitialized = -32002,
+ UnknownErrorCode = -32001,
+
+ // Defined by the protocol.
+ RequestCancelled = -32800
+ };
+
+#define CASE_ERRORCODES(x) case ErrorCodes::x: return QLatin1String(#x)
+ static QString errorCodesToString(int code)
+ {
+ switch (code) {
+ CASE_ERRORCODES(ParseError);
+ CASE_ERRORCODES(InvalidRequest);
+ CASE_ERRORCODES(MethodNotFound);
+ CASE_ERRORCODES(InvalidParams);
+ CASE_ERRORCODES(InternalError);
+ CASE_ERRORCODES(serverErrorStart);
+ CASE_ERRORCODES(serverErrorEnd);
+ CASE_ERRORCODES(ServerNotInitialized);
+ CASE_ERRORCODES(RequestCancelled);
+ default:
+ return QCoreApplication::translate("QtC::LanguageClient", "Error %1").arg(code);
+ }
+ }
+#undef CASE_ERRORCODES
+};
+
+template <typename Result, typename ErrorDataType>
+class Response : public JsonRpcMessage
+{
+public:
+ explicit Response(const MessageId &id) { setId(id); }
+ using JsonRpcMessage::JsonRpcMessage;
+
+ MessageId id() const
+ { return MessageId(m_jsonObject.value(idKey)); }
+ void setId(MessageId id)
+ { this->m_jsonObject.insert(idKey, id); }
+
+ std::optional<Result> result() const
+ {
+ const QJsonValue &result = m_jsonObject.value(resultKey);
+ if (result.isUndefined())
+ return std::nullopt;
+ return std::make_optional(Result(result));
+ }
+ void setResult(const Result &result) { m_jsonObject.insert(resultKey, QJsonValue(result)); }
+ void clearResult() { m_jsonObject.remove(resultKey); }
+
+ using Error = ResponseError<ErrorDataType>;
+ std::optional<Error> error() const
+ {
+ const QJsonValue &val = m_jsonObject.value(errorKey);
+ return val.isUndefined() ? std::nullopt : std::make_optional(fromJsonValue<Error>(val));
+ }
+ void setError(const Error &error)
+ {
+ m_jsonObject.insert(errorKey, QJsonValue(error));
+ }
+ void clearError() { m_jsonObject.remove(errorKey); }
+
+ bool isValid(QString *errorMessage) const override
+ { return JsonRpcMessage::isValid(errorMessage) && id().isValid(); }
+};
+
+template<typename ErrorDataType>
+class Response<std::nullptr_t, ErrorDataType> : public JsonRpcMessage
+{
+public:
+ explicit Response(const MessageId &id) { setId(id); }
+ using JsonRpcMessage::JsonRpcMessage;
+
+ MessageId id() const
+ { return MessageId(m_jsonObject.value(idKey)); }
+ void setId(MessageId id)
+ { this->m_jsonObject.insert(idKey, id); }
+
+ std::optional<std::nullptr_t> result() const
+ {
+ return m_jsonObject.value(resultKey).isNull() ? std::make_optional(nullptr) : std::nullopt;
+ }
+ void setResult(const std::nullptr_t &) { m_jsonObject.insert(resultKey, QJsonValue::Null); }
+ void clearResult() { m_jsonObject.remove(resultKey); }
+
+ using Error = ResponseError<ErrorDataType>;
+ std::optional<Error> error() const
+ {
+ const QJsonValue &val = m_jsonObject.value(errorKey);
+ return val.isUndefined() ? std::nullopt : std::make_optional(fromJsonValue<Error>(val));
+ }
+ void setError(const Error &error)
+ { m_jsonObject.insert(errorKey, QJsonValue(error)); }
+ void clearError() { m_jsonObject.remove(errorKey); }
+
+ bool isValid(QString *errorMessage) const override
+ { return JsonRpcMessage::isValid(errorMessage) && id().isValid(); }
+};
+
+void LANGUAGESERVERPROTOCOL_EXPORT logElapsedTime(const QString &method, const QElapsedTimer &t);
+
+template <typename Result, typename ErrorDataType, typename Params>
+class Request : public Notification<Params>
+{
+public:
+ Request(const QString &methodName, const Params &params)
+ : Notification<Params>(methodName, params)
+ { setId(MessageId(QUuid::createUuid().toString())); }
+ explicit Request(const QJsonObject &jsonObject) : Notification<Params>(jsonObject) { }
+ explicit Request(QJsonObject &&jsonObject) : Notification<Params>(std::move(jsonObject)) { }
+
+ MessageId id() const
+ { return MessageId(JsonRpcMessage::m_jsonObject.value(idKey)); }
+ void setId(const MessageId &id)
+ { JsonRpcMessage::m_jsonObject.insert(idKey, id); }
+
+ using Response = lsp::Response<Result, ErrorDataType>;
+ using ResponseCallback = std::function<void(Response)>;
+ void setResponseCallback(const ResponseCallback &callback)
+ { m_callBack = callback; }
+
+ std::optional<ResponseHandler> responseHandler() const final
+ {
+ QElapsedTimer timer;
+ timer.start();
+ auto callback = [callback = m_callBack, method = this->method(), t = std::move(timer)]
+ (const JsonRpcMessage &message) {
+ if (!callback)
+ return;
+ logElapsedTime(method, t);
+
+ callback(Response(message.toJsonObject()));
+ };
+ return std::make_optional(ResponseHandler{id(), callback});
+ }
+
+ bool isValid(QString *errorMessage) const override
+ {
+ if (!Notification<Params>::isValid(errorMessage))
+ return false;
+ if (id().isValid())
+ return true;
+ if (errorMessage)
+ *errorMessage = QCoreApplication::translate("QtC::LanguageServerProtocol",
+ "No ID set in \"%1\".").arg(this->method());
+ return false;
+ }
+
+private:
+ ResponseCallback m_callBack;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT CancelParameter : public JsonObject
+{
+public:
+ explicit CancelParameter(const MessageId &id) { setId(id); }
+ CancelParameter() = default;
+ using JsonObject::JsonObject;
+
+ MessageId id() const { return typedValue<MessageId>(idKey); }
+ void setId(const MessageId &id) { insert(idKey, id); }
+
+ bool isValid() const override { return contains(idKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT CancelRequest : public Notification<CancelParameter>
+{
+public:
+ explicit CancelRequest(const CancelParameter &params);
+ using Notification::Notification;
+ constexpr static const char methodName[] = "$/cancelRequest";
+};
+
+} // namespace lsp
+
+template <typename Error>
+inline QDebug operator<<(QDebug stream, const lsp::ResponseError<Error> &error)
+{
+ stream.nospace() << error.toString();
+ return stream;
+}
+
+Q_DECLARE_METATYPE(lsp::JsonRpcMessage)
diff --git a/src/shared/lsp/languagefeatures.cpp b/src/shared/lsp/languagefeatures.cpp
new file mode 100644
index 000000000..8ca771f68
--- /dev/null
+++ b/src/shared/lsp/languagefeatures.cpp
@@ -0,0 +1,399 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "languagefeatures.h"
+
+#include <cstddef>
+
+namespace lsp {
+
+constexpr const char HoverRequest::methodName[];
+constexpr const char GotoDefinitionRequest::methodName[];
+constexpr const char GotoTypeDefinitionRequest::methodName[];
+constexpr const char GotoImplementationRequest::methodName[];
+constexpr const char FindReferencesRequest::methodName[];
+constexpr const char DocumentHighlightsRequest::methodName[];
+constexpr const char DocumentSymbolsRequest::methodName[];
+constexpr const char CodeActionRequest::methodName[];
+constexpr const char CodeLensRequest::methodName[];
+constexpr const char CodeLensResolveRequest::methodName[];
+constexpr const char DocumentLinkRequest::methodName[];
+constexpr const char DocumentLinkResolveRequest::methodName[];
+constexpr const char DocumentColorRequest::methodName[];
+constexpr const char ColorPresentationRequest::methodName[];
+constexpr const char DocumentFormattingRequest::methodName[];
+constexpr const char DocumentRangeFormattingRequest::methodName[];
+constexpr const char DocumentOnTypeFormattingRequest::methodName[];
+constexpr const char RenameRequest::methodName[];
+constexpr const char SignatureHelpRequest::methodName[];
+constexpr const char PrepareRenameRequest::methodName[];
+
+HoverContent Hover::content() const
+{
+ return HoverContent(value(contentsKey));
+}
+
+void Hover::setContent(const HoverContent &content)
+{
+ if (auto val = std::get_if<MarkedString>(&content))
+ insert(contentsKey, *val);
+ else if (auto val = std::get_if<MarkupContent>(&content))
+ insert(contentsKey, *val);
+ else if (auto val = std::get_if<QList<MarkedString>>(&content))
+ insert(contentsKey, LanguageClientArray<MarkedString>(*val).toJson());
+ else
+ QBS_ASSERT("LanguageClient Using unknown type Hover::setContent",;);
+}
+
+HoverRequest::HoverRequest(const TextDocumentPositionParams &params)
+ : Request(methodName, params)
+{ }
+
+std::optional<MarkupOrString> ParameterInformation::documentation() const
+{
+ QJsonValue documentation = value(documentationKey);
+ if (documentation.isUndefined())
+ return std::nullopt;
+ return MarkupOrString(documentation);
+}
+
+GotoDefinitionRequest::GotoDefinitionRequest(const TextDocumentPositionParams &params)
+ : Request(methodName, params)
+{ }
+
+GotoTypeDefinitionRequest::GotoTypeDefinitionRequest(const TextDocumentPositionParams &params)
+ : Request(methodName, params)
+{ }
+
+GotoImplementationRequest::GotoImplementationRequest(const TextDocumentPositionParams &params)
+ : Request(methodName, params)
+{ }
+
+FindReferencesRequest::FindReferencesRequest(const ReferenceParams &params)
+ : Request(methodName, params)
+{ }
+
+DocumentHighlightsRequest::DocumentHighlightsRequest(const TextDocumentPositionParams &params)
+ : Request(methodName, params)
+{ }
+
+DocumentSymbolsRequest::DocumentSymbolsRequest(const DocumentSymbolParams &params)
+ : Request(methodName, params)
+{ }
+
+std::optional<QList<CodeActionKind> > CodeActionParams::CodeActionContext::only() const
+{
+ return optionalArray<CodeActionKind>(onlyKey);
+}
+
+void CodeActionParams::CodeActionContext::setOnly(const QList<CodeActionKind> &only)
+{
+ insertArray(onlyKey, only);
+}
+
+CodeActionRequest::CodeActionRequest(const CodeActionParams &params)
+ : Request(methodName, params)
+{ }
+
+CodeLensRequest::CodeLensRequest(const CodeLensParams &params)
+ : Request(methodName, params)
+{ }
+
+CodeLensResolveRequest::CodeLensResolveRequest(const CodeLens &params)
+ : Request(methodName, params)
+{ }
+
+DocumentLinkRequest::DocumentLinkRequest(const DocumentLinkParams &params)
+ : Request(methodName, params)
+{ }
+
+DocumentLinkResolveRequest::DocumentLinkResolveRequest(const DocumentLink &params)
+ : Request(methodName, params)
+{ }
+
+DocumentColorRequest::DocumentColorRequest(const DocumentColorParams &params)
+ : Request(methodName, params)
+{ }
+
+ColorPresentationRequest::ColorPresentationRequest(const ColorPresentationParams &params)
+ : Request(methodName, params)
+{ }
+
+QHash<QString, DocumentFormattingProperty> FormattingOptions::properties() const
+{
+ QHash<QString, DocumentFormattingProperty> ret;
+ for (const QString &key : keys()) {
+ if (key == tabSizeKey || key == insertSpaceKey)
+ continue;
+ QJsonValue property = value(key.toStdString());
+ if (property.isBool())
+ ret[key] = property.toBool();
+ if (property.isDouble())
+ ret[key] = property.toDouble();
+ if (property.isString())
+ ret[key] = property.toString();
+ }
+ return ret;
+}
+
+void FormattingOptions::setProperty(const std::string_view key, const DocumentFormattingProperty &property)
+{
+ using namespace std;
+ if (auto val = get_if<double>(&property))
+ insert(key, *val);
+ else if (auto val = get_if<QString>(&property))
+ insert(key, *val);
+ else if (auto val = get_if<bool>(&property))
+ insert(key, *val);
+}
+
+DocumentFormattingRequest::DocumentFormattingRequest(const DocumentFormattingParams &params)
+ : Request(methodName, params)
+{ }
+
+DocumentRangeFormattingRequest::DocumentRangeFormattingRequest(
+ const DocumentRangeFormattingParams &params)
+ : Request(methodName, params)
+{ }
+
+bool DocumentOnTypeFormattingParams::isValid() const
+{
+ return contains(textDocumentKey) && contains(positionKey) && contains(chKey)
+ && contains(optionsKey);
+}
+
+DocumentOnTypeFormattingRequest::DocumentOnTypeFormattingRequest(
+ const DocumentOnTypeFormattingParams &params)
+ : Request(methodName, params)
+{ }
+
+PrepareRenameRequest::PrepareRenameRequest(const TextDocumentPositionParams &params)
+ : Request(methodName, params)
+{ }
+
+bool RenameParams::isValid() const
+{
+ return contains(textDocumentKey) && contains(positionKey) && contains(newNameKey);
+}
+
+RenameRequest::RenameRequest(const RenameParams &params)
+ : Request(methodName, params)
+{ }
+
+std::optional<DocumentUri> DocumentLink::target() const
+{
+ if (std::optional<QString> optionalTarget = optionalValue<QString>(targetKey))
+ return std::make_optional(DocumentUri::fromProtocol(*optionalTarget));
+ return std::nullopt;
+}
+
+std::optional<QJsonValue> DocumentLink::data() const
+{
+ return contains(dataKey) ? std::make_optional(value(dataKey)) : std::nullopt;
+}
+
+TextDocumentParams::TextDocumentParams()
+ : TextDocumentParams(TextDocumentIdentifier())
+{ }
+
+TextDocumentParams::TextDocumentParams(const TextDocumentIdentifier &identifier)
+ : JsonObject()
+{
+ setTextDocument(identifier);
+}
+
+GotoResult::GotoResult(const QJsonValue &value)
+{
+ if (value.isArray()) {
+ QList<Location> locations;
+ for (auto arrayValue : value.toArray()) {
+ if (arrayValue.isObject())
+ locations.append(Location(arrayValue.toObject()));
+ }
+ emplace<QList<Location>>(locations);
+ } else if (value.isObject()) {
+ emplace<Location>(value.toObject());
+ } else {
+ emplace<std::nullptr_t>(nullptr);
+ }
+}
+
+template<typename Symbol>
+QList<Symbol> documentSymbolsResultArray(const QJsonArray &array)
+{
+ QList<Symbol> ret;
+ for (const auto &arrayValue : array) {
+ if (arrayValue.isObject())
+ ret << Symbol(arrayValue.toObject());
+ }
+ return ret;
+}
+
+DocumentSymbolsResult::DocumentSymbolsResult(const QJsonValue &value)
+{
+ if (value.isArray()) {
+ QJsonArray array = value.toArray();
+ if (array.isEmpty()) {
+ *this = QList<SymbolInformation>();
+ } else {
+ QJsonObject arrayObject = array.first().toObject();
+ if (arrayObject.contains(rangeKey))
+ *this = documentSymbolsResultArray<DocumentSymbol>(array);
+ else
+ *this = documentSymbolsResultArray<SymbolInformation>(array);
+ }
+ } else {
+ *this = nullptr;
+ }
+}
+
+DocumentHighlightsResult::DocumentHighlightsResult(const QJsonValue &value)
+{
+ if (value.isArray()) {
+ QList<DocumentHighlight> highlights;
+ for (auto arrayValue : value.toArray()) {
+ if (arrayValue.isObject())
+ highlights.append(DocumentHighlight(arrayValue.toObject()));
+ }
+ *this = highlights;
+ } else {
+ *this = nullptr;
+ }
+}
+
+MarkedString::MarkedString(const QJsonValue &value)
+{
+ if (value.isObject())
+ emplace<MarkedLanguageString>(MarkedLanguageString(value.toObject()));
+ else
+ emplace<QString>(value.toString());
+}
+
+bool MarkedString::isValid() const
+{
+ if (auto markedLanguageString = std::get_if<MarkedLanguageString>(this))
+ return markedLanguageString->isValid();
+ return true;
+}
+
+MarkedString::operator QJsonValue() const
+{
+ if (auto val = std::get_if<QString>(this))
+ return *val;
+ if (auto val = std::get_if<MarkedLanguageString>(this))
+ return QJsonValue(*val);
+ return {};
+}
+
+HoverContent::HoverContent(const QJsonValue &value)
+{
+ if (value.isArray()) {
+ emplace<QList<MarkedString>>(LanguageClientArray<MarkedString>(value).toList());
+ } else if (value.isObject()) {
+ const QJsonObject &object = value.toObject();
+ MarkedLanguageString markedLanguageString(object);
+ if (markedLanguageString.isValid())
+ emplace<MarkedString>(markedLanguageString);
+ else
+ emplace<MarkupContent>(MarkupContent(object));
+ } else if (value.isString()) {
+ emplace<MarkedString>(MarkedString(value.toString()));
+ }
+}
+
+bool HoverContent::isValid() const
+{
+ if (std::holds_alternative<MarkedString>(*this))
+ return std::get<MarkedString>(*this).isValid();
+ return true;
+}
+
+DocumentFormattingProperty::DocumentFormattingProperty(const QJsonValue &value)
+{
+ if (value.isBool())
+ *this = value.toBool();
+ if (value.isDouble())
+ *this = value.toDouble();
+ if (value.isString())
+ *this = value.toString();
+}
+
+SignatureHelpRequest::SignatureHelpRequest(const TextDocumentPositionParams &params)
+ : Request(methodName, params)
+{ }
+
+CodeActionResult::CodeActionResult(const QJsonValue &val)
+{
+ using ResultArray = QList<std::variant<Command, CodeAction>>;
+ if (val.isArray()) {
+ const QJsonArray array = val.toArray();
+ ResultArray result;
+ for (const QJsonValue &val : array) {
+ if (val.toObject().value(commandKey).isString()) {
+ const Command command(val);
+ if (command.isValid())
+ result << command;
+ } else {
+ const CodeAction action(val);
+ if (action.isValid())
+ result << action;
+ }
+ }
+ emplace<ResultArray>(result);
+ return;
+ }
+ emplace<std::nullptr_t>(nullptr);
+}
+
+PrepareRenameResult::PrepareRenameResult()
+ : std::variant<PlaceHolderResult, Range, std::nullptr_t>(nullptr)
+{}
+
+PrepareRenameResult::PrepareRenameResult(
+ const std::variant<PlaceHolderResult, Range, std::nullptr_t> &val)
+ : std::variant<PlaceHolderResult, Range, std::nullptr_t>(val)
+{}
+
+PrepareRenameResult::PrepareRenameResult(const PlaceHolderResult &val)
+ : std::variant<PlaceHolderResult, Range, std::nullptr_t>(val)
+
+{}
+
+PrepareRenameResult::PrepareRenameResult(const Range &val)
+ : std::variant<PlaceHolderResult, Range, std::nullptr_t>(val)
+{}
+
+PrepareRenameResult::PrepareRenameResult(const QJsonValue &val)
+{
+ if (val.isNull()) {
+ emplace<std::nullptr_t>(nullptr);
+ } else if (val.isObject()) {
+ const QJsonObject object = val.toObject();
+ if (object.keys().contains(rangeKey))
+ emplace<PlaceHolderResult>(PlaceHolderResult(object));
+ else
+ emplace<Range>(Range(object));
+ }
+}
+
+std::optional<QJsonValue> CodeLens::data() const
+{
+ return contains(dataKey) ? std::make_optional(value(dataKey)) : std::nullopt;
+}
+
+HoverResult::HoverResult(const QJsonValue &value)
+{
+ if (value.isObject())
+ emplace<Hover>(Hover(value.toObject()));
+ else
+ emplace<std::nullptr_t>(nullptr);
+}
+
+bool HoverResult::isValid() const
+{
+ if (auto hover = std::get_if<Hover>(this))
+ return hover->isValid();
+ return true;
+}
+
+} // namespace lsp
diff --git a/src/shared/lsp/languagefeatures.h b/src/shared/lsp/languagefeatures.h
new file mode 100644
index 000000000..13e3e9857
--- /dev/null
+++ b/src/shared/lsp/languagefeatures.h
@@ -0,0 +1,836 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "jsonrpcmessages.h"
+
+namespace lsp {
+
+/**
+ * MarkedString can be used to render human readable text. It is either a markdown string
+ * or a code-block that provides a language and a code snippet. The language identifier
+ * is semantically equal to the optional language identifier in fenced code blocks in GitHub
+ * issues. See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting
+ *
+ * The pair of a language and a value is an equivalent to markdown:
+ * ```${language}
+ * ${value}
+ * ```
+ *
+ * Note that markdown strings will be sanitized - that means html will be escaped.
+* @deprecated use MarkupContent instead.
+*/
+class LANGUAGESERVERPROTOCOL_EXPORT MarkedLanguageString : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ QString language() const { return typedValue<QString>(languageKey); }
+ void setLanguage(const QString &language) { insert(languageKey, language); }
+
+ QString value() const { return typedValue<QString>(valueKey); }
+ void setValue(const QString &value) { insert(valueKey, value); }
+
+ bool isValid() const override { return contains(languageKey) && contains(valueKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT MarkedString
+ : public std::variant<QString, MarkedLanguageString>
+{
+public:
+ MarkedString() = default;
+ explicit MarkedString(const MarkedLanguageString &other)
+ : variant(other)
+ {}
+ explicit MarkedString(const QString &other)
+ : variant(other)
+ {}
+ explicit MarkedString(const QJsonValue &value);
+
+ bool isValid() const;
+ operator QJsonValue() const;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT HoverContent
+ : public std::variant<MarkedString, QList<MarkedString>, MarkupContent>
+{
+public:
+ HoverContent() = default;
+ explicit HoverContent(const MarkedString &other) : variant(other) {}
+ explicit HoverContent(const QList<MarkedString> &other) : variant(other) {}
+ explicit HoverContent(const MarkupContent &other) : variant(other) {}
+ explicit HoverContent(const QJsonValue &value);
+ bool isValid() const;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT Hover : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ HoverContent content() const;
+ void setContent(const HoverContent &content);
+
+ std::optional<Range> range() const { return optionalValue<Range>(rangeKey); }
+ void setRange(const Range &range) { insert(rangeKey, range); }
+ void clearRange() { remove(rangeKey); }
+
+ bool isValid() const override { return contains(contentsKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT HoverResult : public std::variant<Hover, std::nullptr_t>
+{
+public:
+ HoverResult() : variant(nullptr) {}
+ explicit HoverResult(const Hover &hover) : variant(hover) {}
+ explicit HoverResult(const QJsonValue &value);
+ bool isValid() const;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT HoverRequest
+ : public Request<HoverResult, std::nullptr_t, TextDocumentPositionParams>
+{
+public:
+ explicit HoverRequest(const TextDocumentPositionParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/hover";
+};
+
+/**
+ * Represents a parameter of a callable-signature. A parameter can
+ * have a label and a doc-comment.
+ */
+class LANGUAGESERVERPROTOCOL_EXPORT ParameterInformation : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ QString label() const { return typedValue<QString>(labelKey); }
+ void setLabel(const QString &label) { insert(labelKey, label); }
+
+ std::optional<MarkupOrString> documentation() const;
+ void setDocumentation(const MarkupOrString &documentation)
+ { insert(documentationKey, documentation.toJson()); }
+ void clearDocumentation() { remove(documentationKey); }
+
+ bool isValid() const override { return contains(labelKey); }
+};
+
+/**
+ * Represents the signature of something callable. A signature
+ * can have a label, like a function-name, a doc-comment, and
+ * a set of parameters.
+ */
+class LANGUAGESERVERPROTOCOL_EXPORT SignatureInformation : public ParameterInformation
+{
+public:
+ using ParameterInformation::ParameterInformation;
+
+ std::optional<QList<ParameterInformation>> parameters() const
+ { return optionalArray<ParameterInformation>(parametersKey); }
+ void setParameters(const QList<ParameterInformation> &parameters)
+ { insertArray(parametersKey, parameters); }
+ void clearParameters() { remove(parametersKey); }
+
+ std::optional<int> activeParameter() const { return optionalValue<int>(activeParameterKey); }
+ void setActiveParameter(int activeParameter) { insert(activeParameterKey, activeParameter); }
+ void clearActiveParameter() { remove(activeParameterKey); }
+};
+
+/**
+ * Signature help represents the signature of something
+ * callable. There can be multiple signature but only one
+ * active and only one active parameter.
+ */
+class LANGUAGESERVERPROTOCOL_EXPORT SignatureHelp : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ /// One or more signatures.
+ QList<SignatureInformation> signatures() const
+ { return array<SignatureInformation>(signaturesKey); }
+ void setSignatures(const QList<SignatureInformation> &signatures)
+ { insertArray(signaturesKey, signatures); }
+
+ /**
+ * The active signature. If omitted or the value lies outside the
+ * range of `signatures` the value defaults to zero or is ignored if
+ * `signatures.length === 0`. Whenever possible implementors should
+ * make an active decision about the active signature and shouldn't
+ * rely on a default value.
+ * In future version of the protocol this property might become
+ * mandatory to better express this.
+ */
+ std::optional<int> activeSignature() const { return optionalValue<int>(activeSignatureKey); }
+ void setActiveSignature(int activeSignature) { insert(activeSignatureKey, activeSignature); }
+ void clearActiveSignature() { remove(activeSignatureKey); }
+
+ /**
+ * The active parameter of the active signature. If omitted or the value
+ * lies outside the range of `signatures[activeSignature].parameters`
+ * defaults to 0 if the active signature has parameters. If
+ * the active signature has no parameters it is ignored.
+ * In future version of the protocol this property might become
+ * mandatory to better express the active parameter if the
+ * active signature does have any.
+ */
+ std::optional<int> activeParameter() const { return optionalValue<int>(activeParameterKey); }
+ void setActiveParameter(int activeParameter) { insert(activeParameterKey, activeParameter); }
+ void clearActiveParameter() { remove(activeParameterKey); }
+
+ bool isValid() const override { return contains(signaturesKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SignatureHelpRequest
+ : public Request<LanguageClientValue<SignatureHelp>, std::nullptr_t, TextDocumentPositionParams>
+{
+public:
+ explicit SignatureHelpRequest(const TextDocumentPositionParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/signatureHelp";
+};
+
+/// The result of a goto request can either be a location, a list of locations or null
+class LANGUAGESERVERPROTOCOL_EXPORT GotoResult
+ : public std::variant<Location, QList<Location>, std::nullptr_t>
+{
+public:
+ explicit GotoResult(const QJsonValue &value);
+ using variant::variant;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT GotoDefinitionRequest
+ : public Request<GotoResult, std::nullptr_t, TextDocumentPositionParams>
+{
+public:
+ explicit GotoDefinitionRequest(const TextDocumentPositionParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/definition";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT GotoTypeDefinitionRequest : public Request<
+ GotoResult, std::nullptr_t, TextDocumentPositionParams>
+{
+public:
+ explicit GotoTypeDefinitionRequest(const TextDocumentPositionParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/typeDefinition";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT GotoImplementationRequest : public Request<
+ GotoResult, std::nullptr_t, TextDocumentPositionParams>
+{
+public:
+ explicit GotoImplementationRequest(const TextDocumentPositionParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/implementation";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ReferenceParams : public TextDocumentPositionParams
+{
+public:
+ using TextDocumentPositionParams::TextDocumentPositionParams;
+
+ class ReferenceContext : public JsonObject
+ {
+ public:
+ explicit ReferenceContext(bool includeDeclaration)
+ { setIncludeDeclaration(includeDeclaration); }
+ ReferenceContext() = default;
+ using JsonObject::JsonObject;
+ bool includeDeclaration() const { return typedValue<bool>(includeDeclarationKey); }
+ void setIncludeDeclaration(bool includeDeclaration)
+ { insert(includeDeclarationKey, includeDeclaration); }
+
+ bool isValid() const override { return contains(includeDeclarationKey); }
+ };
+
+ ReferenceContext context() const { return typedValue<ReferenceContext>(contextKey); }
+ void setContext(const ReferenceContext &context) { insert(contextKey, context); }
+
+ bool isValid() const override
+ { return TextDocumentPositionParams::isValid() && contains(contextKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT FindReferencesRequest : public Request<
+ LanguageClientArray<Location>, std::nullptr_t, ReferenceParams>
+{
+public:
+ explicit FindReferencesRequest(const ReferenceParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/references";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentHighlight : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ enum DocumentHighlightKind {
+ Text = 1,
+ Read = 2,
+ Write = 3
+ };
+
+ Range range() const { return typedValue<Range>(rangeKey); }
+ void setRange(const Range &range) { insert(rangeKey, range); }
+
+ std::optional<int> kind() const { return optionalValue<int>(kindKey); }
+ void setKind(int kind) { insert(kindKey, kind); }
+ void clearKind() { remove(kindKey); }
+
+ bool isValid() const override { return contains(rangeKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentHighlightsResult
+ : public std::variant<QList<DocumentHighlight>, std::nullptr_t>
+{
+public:
+ using variant::variant;
+ DocumentHighlightsResult() : variant(nullptr) {}
+ explicit DocumentHighlightsResult(const QJsonValue &value);
+ using variant::operator=;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentHighlightsRequest : public Request<
+ DocumentHighlightsResult, std::nullptr_t, TextDocumentPositionParams>
+{
+public:
+ explicit DocumentHighlightsRequest(const TextDocumentPositionParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/documentHighlight";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentParams : public JsonObject
+{
+public:
+ TextDocumentParams();
+ explicit TextDocumentParams(const TextDocumentIdentifier &identifier);
+ using JsonObject::JsonObject;
+
+ TextDocumentIdentifier textDocument() const
+ { return typedValue<TextDocumentIdentifier>(textDocumentKey); }
+ void setTextDocument(const TextDocumentIdentifier &textDocument)
+ { insert(textDocumentKey, textDocument); }
+
+ bool isValid() const override { return contains(textDocumentKey); }
+};
+
+using DocumentSymbolParams = TextDocumentParams;
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentSymbolsResult
+ : public std::variant<QList<SymbolInformation>, QList<DocumentSymbol>, std::nullptr_t>
+{
+public:
+ using variant::variant;
+ DocumentSymbolsResult() : variant(nullptr) {}
+ explicit DocumentSymbolsResult(const QJsonValue &value);
+ DocumentSymbolsResult(const DocumentSymbolsResult &other) : variant(other) {}
+ DocumentSymbolsResult(DocumentSymbolsResult &&other) : variant(std::move(other)) {}
+
+ using variant::operator=;
+ DocumentSymbolsResult &operator =(DocumentSymbolsResult &&other)
+ {
+ variant::operator=(std::move(other));
+ return *this;
+ }
+ DocumentSymbolsResult &operator =(const DocumentSymbolsResult &other)
+ {
+ variant::operator=(other);
+ return *this;
+ }
+ // Needed to make it usable in Qt 6 signals.
+ bool operator<(const DocumentSymbolsResult &other) const = delete;
+};
+
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentSymbolsRequest
+ : public Request<DocumentSymbolsResult, std::nullptr_t, DocumentSymbolParams>
+{
+public:
+ explicit DocumentSymbolsRequest(const DocumentSymbolParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/documentSymbol";
+};
+
+/**
+ * The kind of a code action.
+ *
+ * Kinds are a hierarchical list of identifiers separated by `.`, e.g. `"refactor.extract.function"`.
+ *
+ * The set of kinds is open and client needs to announce the kinds it supports to the server during
+ * initialization.
+ */
+
+using CodeActionKind = QString;
+
+/**
+ * A set of predefined code action kinds
+ */
+
+namespace CodeActionKinds {
+constexpr char QuickFix[] = "quickfix";
+constexpr char Refactor[] = "refactor";
+constexpr char RefactorExtract[] = "refactor.extract";
+constexpr char RefactorInline[] = "refactor.inline";
+constexpr char RefactorRewrite[] = "refactor.rewrite";
+constexpr char Source[] = "source";
+constexpr char SourceOrganizeImports[] = "source.organizeImports";
+}
+
+class LANGUAGESERVERPROTOCOL_EXPORT CodeActionParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ class LANGUAGESERVERPROTOCOL_EXPORT CodeActionContext : public JsonObject
+ {
+ public:
+ using JsonObject::JsonObject;
+
+ QList<Diagnostic> diagnostics() const { return array<Diagnostic>(diagnosticsKey); }
+ void setDiagnostics(const QList<Diagnostic> &diagnostics)
+ { insertArray(diagnosticsKey, diagnostics); }
+
+ std::optional<QList<CodeActionKind>> only() const;
+ void setOnly(const QList<CodeActionKind> &only);
+ void clearOnly() { remove(onlyKey); }
+
+ bool isValid() const override { return contains(diagnosticsKey); }
+ };
+
+ TextDocumentIdentifier textDocument() const
+ { return typedValue<TextDocumentIdentifier>(textDocumentKey); }
+ void setTextDocument(const TextDocumentIdentifier &textDocument)
+ { insert(textDocumentKey, textDocument); }
+
+ Range range() const { return typedValue<Range>(rangeKey); }
+ void setRange(const Range &range) { insert(rangeKey, range); }
+
+ CodeActionContext context() const { return typedValue<CodeActionContext>(contextKey); }
+ void setContext(const CodeActionContext &context) { insert(contextKey, context); }
+
+ bool isValid() const override
+ { return contains(textDocumentKey) && contains(rangeKey) && contains(contextKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT CodeAction : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ QString title() const { return typedValue<QString>(titleKey); }
+ void setTitle(QString title) { insert(titleKey, title); }
+
+ std::optional<CodeActionKind> kind() const { return optionalValue<CodeActionKind>(kindKey); }
+ void setKind(const CodeActionKind &kind) { insert(kindKey, kind); }
+ void clearKind() { remove(kindKey); }
+
+ std::optional<QList<Diagnostic>> diagnostics() const
+ { return optionalArray<Diagnostic>(diagnosticsKey); }
+ void setDiagnostics(const QList<Diagnostic> &diagnostics)
+ { insertArray(diagnosticsKey, diagnostics); }
+ void clearDiagnostics() { remove(diagnosticsKey); }
+
+ std::optional<WorkspaceEdit> edit() const { return optionalValue<WorkspaceEdit>(editKey); }
+ void setEdit(const WorkspaceEdit &edit) { insert(editKey, edit); }
+ void clearEdit() { remove(editKey); }
+
+ std::optional<Command> command() const { return optionalValue<Command>(commandKey); }
+ void setCommand(const Command &command) { insert(commandKey, command); }
+ void clearCommand() { remove(commandKey); }
+
+ bool isValid() const override { return contains(titleKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT CodeActionResult
+ : public std::variant<QList<std::variant<Command, CodeAction>>, std::nullptr_t>
+{
+public:
+ using variant::variant;
+ explicit CodeActionResult(const QJsonValue &val);
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT CodeActionRequest : public Request<
+ CodeActionResult, std::nullptr_t, CodeActionParams>
+{
+public:
+ explicit CodeActionRequest(const CodeActionParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/codeAction";
+};
+
+using CodeLensParams = TextDocumentParams;
+
+class LANGUAGESERVERPROTOCOL_EXPORT CodeLens : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ Range range() const { return typedValue<Range>(rangeKey); }
+ void setRange(const Range &range) { insert(rangeKey, range); }
+
+ std::optional<Command> command() const { return optionalValue<Command>(commandKey); }
+ void setCommand(const Command &command) { insert(commandKey, command); }
+ void clearCommand() { remove(commandKey); }
+
+ std::optional<QJsonValue> data() const;
+ void setData(const QJsonValue &data) { insert(dataKey, data); }
+ void clearData() { remove(dataKey); }
+
+ bool isValid() const override { return contains(rangeKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT CodeLensRequest : public Request<
+ LanguageClientArray<CodeLens>, std::nullptr_t, CodeLensParams>
+{
+public:
+ explicit CodeLensRequest(const CodeLensParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/codeLens";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT CodeLensResolveRequest : public Request<
+ CodeLens, std::nullptr_t, CodeLens>
+{
+public:
+ explicit CodeLensResolveRequest(const CodeLens &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "codeLens/resolve";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentLink : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ Range range() const { return typedValue<Range>(rangeKey); }
+ void setRange(const Range &range) { insert(rangeKey, range); }
+
+ std::optional<DocumentUri> target() const;
+ void setTarget(const DocumentUri &target) { insert(targetKey, target.toString()); }
+ void clearTarget() { remove(targetKey); }
+
+ std::optional<QJsonValue> data() const;
+ void setData(const QJsonValue &data) { insert(dataKey, data); }
+ void clearData() { remove(dataKey); }
+
+ bool isValid() const override { return contains(rangeKey); }
+};
+
+using DocumentLinkParams = TextDocumentParams;
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentLinkRequest : public Request<
+ LanguageClientValue<DocumentLink>, std::nullptr_t, DocumentLinkParams>
+{
+public:
+ explicit DocumentLinkRequest(const DocumentLinkParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/documentLink";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentLinkResolveRequest : public Request<
+ DocumentLink, std::nullptr_t, DocumentLink>
+{
+public:
+ explicit DocumentLinkResolveRequest(const DocumentLink &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "documentLink/resolve";
+};
+
+using DocumentColorParams = TextDocumentParams;
+
+class LANGUAGESERVERPROTOCOL_EXPORT Color : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ double red() const { return typedValue<double>(redKey); }
+ void setRed(double red) { insert(redKey, red); }
+
+ double green() const { return typedValue<double>(greenKey); }
+ void setGreen(double green) { insert(greenKey, green); }
+
+ double blue() const { return typedValue<double>(blueKey); }
+ void setBlue(double blue) { insert(blueKey, blue); }
+
+ double alpha() const { return typedValue<double>(alphaKey); }
+ void setAlpha(double alpha) { insert(alphaKey, alpha); }
+
+ bool isValid() const override
+ { return contains(redKey) && contains(greenKey) && contains(blueKey) && contains(alphaKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ColorInformation : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ Range range() const { return typedValue<Range>(rangeKey); }
+ void setRange(Range range) { insert(rangeKey, range); }
+
+ Color color() const { return typedValue<Color>(colorKey); }
+ void setColor(const Color &color) { insert(colorKey, color); }
+
+ bool isValid() const override { return contains(rangeKey) && contains(colorKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentColorRequest : public Request<
+ QList<ColorInformation>, std::nullptr_t, DocumentColorParams>
+{
+public:
+ explicit DocumentColorRequest(const DocumentColorParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/documentColor";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ColorPresentationParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ TextDocumentIdentifier textDocument() const
+ { return typedValue<TextDocumentIdentifier>(textDocumentKey); }
+ void setTextDocument(const TextDocumentIdentifier &textDocument)
+ { insert(textDocumentKey, textDocument); }
+
+ Color colorInfo() const { return typedValue<Color>(colorInfoKey); }
+ void setColorInfo(const Color &colorInfo) { insert(colorInfoKey, colorInfo); }
+
+ Range range() const { return typedValue<Range>(rangeKey); }
+ void setRange(const Range &range) { insert(rangeKey, range); }
+
+ bool isValid() const override
+ { return contains(textDocumentKey) && contains(colorInfoKey) && contains(rangeKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ColorPresentation : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ QString label() const { return typedValue<QString>(labelKey); }
+ void setLabel(const QString &label) { insert(labelKey, label); }
+
+ std::optional<TextEdit> textEdit() const { return optionalValue<TextEdit>(textEditKey); }
+ void setTextEdit(const TextEdit &textEdit) { insert(textEditKey, textEdit); }
+ void clearTextEdit() { remove(textEditKey); }
+
+ std::optional<QList<TextEdit>> additionalTextEdits() const
+ { return optionalArray<TextEdit>(additionalTextEditsKey); }
+ void setAdditionalTextEdits(const QList<TextEdit> &additionalTextEdits)
+ { insertArray(additionalTextEditsKey, additionalTextEdits); }
+ void clearAdditionalTextEdits() { remove(additionalTextEditsKey); }
+
+ bool isValid() const override { return contains(labelKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ColorPresentationRequest : public Request<
+ QList<ColorPresentation>, std::nullptr_t, ColorPresentationParams>
+{
+public:
+ explicit ColorPresentationRequest(const ColorPresentationParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/colorPresentation";
+};
+
+class DocumentFormattingProperty : public std::variant<bool, double, QString>
+{
+public:
+ DocumentFormattingProperty() = default;
+ explicit DocumentFormattingProperty(const QJsonValue &value);
+ explicit DocumentFormattingProperty(const DocumentFormattingProperty &other)
+ : std::variant<bool, double, QString>(other) {}
+
+ using variant::variant;
+ using variant::operator=;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT FormattingOptions : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ int tabSize() const { return typedValue<int>(tabSizeKey); }
+ void setTabSize(int tabSize) { insert(tabSizeKey, tabSize); }
+
+ bool insertSpace() const { return typedValue<bool>(insertSpaceKey); }
+ void setInsertSpace(bool insertSpace) { insert(insertSpaceKey, insertSpace); }
+
+ std::optional<bool> trimTrailingWhitespace() const
+ { return optionalValue<bool>(trimTrailingWhitespaceKey); }
+ void setTrimTrailingWhitespace(bool trimTrailingWhitespace)
+ { insert(trimTrailingWhitespaceKey, trimTrailingWhitespace); }
+ void clearTrimTrailingWhitespace() { remove(trimTrailingWhitespaceKey); }
+
+ std::optional<bool> insertFinalNewline() const
+ { return optionalValue<bool>(insertFinalNewlineKey); }
+ void setInsertFinalNewline(bool insertFinalNewline)
+ { insert(insertFinalNewlineKey, insertFinalNewline); }
+ void clearInsertFinalNewline() { remove(insertFinalNewlineKey); }
+
+ std::optional<bool> trimFinalNewlines() const
+ { return optionalValue<bool>(trimFinalNewlinesKey); }
+ void setTrimFinalNewlines(bool trimFinalNewlines)
+ { insert(trimFinalNewlinesKey, trimFinalNewlines); }
+ void clearTrimFinalNewlines() { remove(trimFinalNewlinesKey); }
+
+ QHash<QString, DocumentFormattingProperty> properties() const;
+ void setProperty(const std::string_view key, const DocumentFormattingProperty &property);
+ void removeProperty(const std::string_view &key) { remove(key); }
+
+ bool isValid() const override { return contains(insertSpaceKey) && contains(tabSizeKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentFormattingParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ TextDocumentIdentifier textDocument() const
+ { return typedValue<TextDocumentIdentifier>(textDocumentKey); }
+ void setTextDocument(const TextDocumentIdentifier &textDocument)
+ { insert(textDocumentKey, textDocument); }
+
+ FormattingOptions options() const { return typedValue<FormattingOptions>(optionsKey); }
+ void setOptions(const FormattingOptions &options) { insert(optionsKey, options); }
+
+ bool isValid() const override { return contains(textDocumentKey) && contains(optionsKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentFormattingRequest : public Request<
+ LanguageClientArray<TextEdit>, std::nullptr_t, DocumentFormattingParams>
+{
+public:
+ explicit DocumentFormattingRequest(const DocumentFormattingParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/formatting";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentRangeFormattingParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ TextDocumentIdentifier textDocument() const
+ { return typedValue<TextDocumentIdentifier>(textDocumentKey); }
+ void setTextDocument(const TextDocumentIdentifier &textDocument)
+ { insert(textDocumentKey, textDocument); }
+
+ Range range() const { return typedValue<Range>(rangeKey); }
+ void setRange(const Range &range) { insert(rangeKey, range); }
+
+ FormattingOptions options() const { return typedValue<FormattingOptions>(optionsKey); }
+ void setOptions(const FormattingOptions &options) { insert(optionsKey, options); }
+
+ bool isValid() const override
+ { return contains(textDocumentKey) && contains(rangeKey) && contains(optionsKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentRangeFormattingRequest : public Request<
+ LanguageClientArray<TextEdit>, std::nullptr_t, DocumentRangeFormattingParams>
+{
+public:
+ explicit DocumentRangeFormattingRequest(const DocumentRangeFormattingParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/rangeFormatting";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentOnTypeFormattingParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ TextDocumentIdentifier textDocument() const
+ { return typedValue<TextDocumentIdentifier>(textDocumentKey); }
+ void setTextDocument(const TextDocumentIdentifier &textDocument)
+ { insert(textDocumentKey, textDocument); }
+
+ Position position() const { return typedValue<Position>(positionKey); }
+ void setPosition(const Position &position) { insert(positionKey, position); }
+
+ QString ch() const { return typedValue<QString>(chKey); }
+ void setCh(const QString &ch) { insert(chKey, ch); }
+
+ FormattingOptions options() const { return typedValue<FormattingOptions>(optionsKey); }
+ void setOptions(const FormattingOptions &options) { insert(optionsKey, options); }
+
+ bool isValid() const override;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentOnTypeFormattingRequest : public Request<
+ LanguageClientArray<TextEdit>, std::nullptr_t, DocumentOnTypeFormattingParams>
+{
+public:
+ explicit DocumentOnTypeFormattingRequest(const DocumentOnTypeFormattingParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/onTypeFormatting";
+};
+
+class PlaceHolderResult : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ Range range() const { return typedValue<Range>(rangeKey); }
+ void setRange(const Range &range) { insert(rangeKey, range); }
+
+ QString placeHolder() const { return typedValue<QString>(placeHolderKey); }
+ void setPlaceHolder(const QString &placeHolder) { insert(placeHolderKey, placeHolder); }
+
+ bool isValid() const override { return contains(rangeKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT PrepareRenameResult
+ : public std::variant<PlaceHolderResult, Range, std::nullptr_t>
+{
+public:
+ PrepareRenameResult();
+ PrepareRenameResult(const std::variant<PlaceHolderResult, Range, std::nullptr_t> &val);
+ explicit PrepareRenameResult(const PlaceHolderResult &val);
+ explicit PrepareRenameResult(const Range &val);
+ explicit PrepareRenameResult(const QJsonValue &val);
+
+ bool isValid() const;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT PrepareRenameRequest
+ : public Request<PrepareRenameResult, std::nullptr_t, TextDocumentPositionParams>
+{
+public:
+ explicit PrepareRenameRequest(const TextDocumentPositionParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/prepareRename";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT RenameParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ TextDocumentIdentifier textDocument() const
+ { return typedValue<TextDocumentIdentifier>(textDocumentKey); }
+ void setTextDocument(const TextDocumentIdentifier &textDocument)
+ { insert(textDocumentKey, textDocument); }
+
+ Position position() const { return typedValue<Position>(positionKey); }
+ void setPosition(const Position &position) { insert(positionKey, position); }
+
+ QString newName() const { return typedValue<QString>(newNameKey); }
+ void setNewName(const QString &newName) { insert(newNameKey, newName); }
+
+ bool isValid() const override;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT RenameRequest : public Request<
+ WorkspaceEdit, std::nullptr_t, RenameParams>
+{
+public:
+ explicit RenameRequest(const RenameParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/rename";
+};
+
+} // namespace LanguageClient
diff --git a/src/shared/lsp/languageserverprotocol_global.h b/src/shared/lsp/languageserverprotocol_global.h
new file mode 100644
index 000000000..7f06f1216
--- /dev/null
+++ b/src/shared/lsp/languageserverprotocol_global.h
@@ -0,0 +1,14 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <QtGlobal>
+
+#if defined(LANGUAGESERVERPROTOCOL_LIBRARY)
+# define LANGUAGESERVERPROTOCOL_EXPORT Q_DECL_EXPORT
+#elif defined(LANGUAGESERVERPROTOCOL_STATIC_LIBRARY)
+# define LANGUAGESERVERPROTOCOL_EXPORT
+#else
+# define LANGUAGESERVERPROTOCOL_EXPORT Q_DECL_IMPORT
+#endif
diff --git a/src/shared/lsp/languageserverprotocoltr.h b/src/shared/lsp/languageserverprotocoltr.h
new file mode 100644
index 000000000..a4e2f324c
--- /dev/null
+++ b/src/shared/lsp/languageserverprotocoltr.h
@@ -0,0 +1,15 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <QCoreApplication>
+
+namespace lsp {
+
+struct Tr
+{
+ Q_DECLARE_TR_FUNCTIONS(QtC::LanguageServerProtocol)
+};
+
+} // LanguageServerProtocol
diff --git a/src/shared/lsp/link.cpp b/src/shared/lsp/link.cpp
new file mode 100644
index 000000000..e25b828d7
--- /dev/null
+++ b/src/shared/lsp/link.cpp
@@ -0,0 +1,35 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "link.h"
+
+#include "textutils.h"
+
+namespace lsp::Utils {
+
+/*!
+ Returns the Link to \a filePath.
+ If \a canContainLineNumber is true the line number, and column number components
+ are extracted from the \a filePath's \c path() and the found \a postfix is set.
+
+ The following patterns are supported: \c {filepath.txt:19},
+ \c{filepath.txt:19:12}, \c {filepath.txt+19},
+ \c {filepath.txt+19+12}, and \c {filepath.txt(19)}.
+*/
+
+Link Link::fromString(const QString &filePathWithNumbers, bool canContainLineNumber)
+{
+ Link link;
+ if (!canContainLineNumber) {
+ link.targetFilePath = FilePath::fromUserInput(filePathWithNumbers);
+ } else {
+ int postfixPos = -1;
+ const Text::Position pos = Text::Position::fromFileName(filePathWithNumbers, postfixPos);
+ link.targetFilePath = FilePath::fromUserInput(filePathWithNumbers.left(postfixPos));
+ link.targetLine = pos.line;
+ link.targetColumn = pos.column;
+ }
+ return link;
+}
+
+} // namespace lsp::Utils
diff --git a/src/shared/lsp/link.h b/src/shared/lsp/link.h
new file mode 100644
index 000000000..eaafe280c
--- /dev/null
+++ b/src/shared/lsp/link.h
@@ -0,0 +1,78 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "filepath.h"
+
+#include <QMetaType>
+#include <QMultiHash>
+#include <QString>
+
+#include <functional>
+
+namespace lsp::Utils {
+
+class Link
+{
+public:
+ Link() = default;
+ Link(const FilePath &filePath, int line = 0, int column = 0)
+ : targetFilePath(filePath)
+ , targetLine(line)
+ , targetColumn(column)
+ {}
+
+ static Link fromString(const QString &filePathWithNumbers, bool canContainLineNumber = false);
+
+ bool hasValidTarget() const
+ {
+ if (!targetFilePath.isEmpty())
+ return true;
+ return !targetFilePath.scheme().isEmpty() || !targetFilePath.host().isEmpty();
+ }
+
+ bool hasValidLinkText() const
+ { return linkTextStart != linkTextEnd; }
+
+ bool operator==(const Link &other) const
+ {
+ return hasSameLocation(other)
+ && linkTextStart == other.linkTextStart
+ && linkTextEnd == other.linkTextEnd;
+ }
+ bool operator!=(const Link &other) const { return !(*this == other); }
+
+ bool hasSameLocation(const Link &other) const
+ {
+ return targetFilePath == other.targetFilePath
+ && targetLine == other.targetLine
+ && targetColumn == other.targetColumn;
+ }
+
+ friend size_t qHash(const Link &l, uint seed = 0)
+ { return QT_PREPEND_NAMESPACE(qHash)(l.targetFilePath, seed)
+ | QT_PREPEND_NAMESPACE(qHash(l.targetLine, seed))
+ | QT_PREPEND_NAMESPACE(qHash(l.targetColumn, seed)); }
+
+ int linkTextStart = -1;
+ int linkTextEnd = -1;
+
+ FilePath targetFilePath;
+ int targetLine = 0;
+ int targetColumn = 0;
+};
+
+using LinkHandler = std::function<void(const Link &)>;
+using Links = QList<Link>;
+
+} // namespace lsp::Utils
+
+namespace std {
+
+template<> struct hash<lsp::Utils::Link>
+{
+ size_t operator()(const lsp::Utils::Link &fn) const { return qHash(fn); }
+};
+
+} // std
diff --git a/src/shared/lsp/lsp.qbs b/src/shared/lsp/lsp.qbs
new file mode 100644
index 000000000..95323d332
--- /dev/null
+++ b/src/shared/lsp/lsp.qbs
@@ -0,0 +1,72 @@
+import qbs.Utilities
+
+QbsStaticLibrary {
+ name: "qtclsp"
+
+ Depends { name: "qbscore"; cpp.link: false }
+
+ Depends {
+ condition: Utilities.versionCompare(Qt.core.version, "6") >= 0
+ name: "Qt.core5compat"
+ }
+
+ cpp.defines: base.filter(function(d) { return d !== "QT_NO_CAST_FROM_ASCII"; })
+ .concat("LANGUAGESERVERPROTOCOL_STATIC_LIBRARY")
+
+ files: [
+ "algorithm.h",
+ "basemessage.cpp",
+ "basemessage.h",
+ "callhierarchy.cpp",
+ "callhierarchy.h",
+ "client.cpp",
+ "client.h",
+ "clientcapabilities.cpp",
+ "clientcapabilities.h",
+ "completion.cpp",
+ "completion.h",
+ "diagnostics.cpp",
+ "diagnostics.h",
+ "filepath.h",
+ "initializemessages.cpp",
+ "initializemessages.h",
+ "jsonkeys.h",
+ "jsonobject.cpp",
+ "jsonobject.h",
+ "jsonrpcmessages.cpp",
+ "jsonrpcmessages.h",
+ "languagefeatures.cpp",
+ "languagefeatures.h",
+ "languageserverprotocol_global.h",
+ "languageserverprotocoltr.h",
+ "link.cpp",
+ "link.h",
+ "lsptypes.cpp",
+ "lsptypes.h",
+ "lsputils.cpp",
+ "lsputils.h",
+ "messages.cpp",
+ "messages.h",
+ "predicates.h",
+ "progresssupport.cpp",
+ "progresssupport.h",
+ "semantictokens.cpp",
+ "semantictokens.h",
+ "servercapabilities.cpp",
+ "servercapabilities.h",
+ "shutdownmessages.cpp",
+ "shutdownmessages.h",
+ "textsynchronization.cpp",
+ "textsynchronization.h",
+ "textutils.cpp",
+ "textutils.h",
+ "workspace.cpp",
+ "workspace.h",
+ ]
+
+ Export {
+ Depends { name: "cpp" }
+ cpp.defines: "LANGUAGESERVERPROTOCOL_STATIC_LIBRARY"
+ cpp.includePaths: exportingProduct.sourceDirectory + "/.."
+ }
+}
diff --git a/src/shared/lsp/lsptypes.cpp b/src/shared/lsp/lsptypes.cpp
new file mode 100644
index 000000000..751fc4e3d
--- /dev/null
+++ b/src/shared/lsp/lsptypes.cpp
@@ -0,0 +1,364 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "lsptypes.h"
+
+#include "languageserverprotocoltr.h"
+#include "lsputils.h"
+#include "textutils.h"
+
+#include <QFile>
+#include <QHash>
+#include <QJsonArray>
+#include <QMap>
+#include <QRegularExpression>
+#include <QVector>
+
+namespace lsp {
+
+std::optional<DiagnosticSeverity> Diagnostic::severity() const
+{
+ if (auto val = optionalValue<int>(severityKey))
+ return std::make_optional(static_cast<DiagnosticSeverity>(*val));
+ return std::nullopt;
+}
+
+std::optional<Diagnostic::Code> Diagnostic::code() const
+{
+ QJsonValue codeValue = value(codeKey);
+ auto it = find(codeKey);
+ if (codeValue.isUndefined())
+ return std::nullopt;
+ QJsonValue::Type type = it.value().type();
+ if (type != QJsonValue::String && type != QJsonValue::Double)
+ return std::make_optional(Code(QString()));
+ return std::make_optional(codeValue.isDouble() ? Code(codeValue.toInt())
+ : Code(codeValue.toString()));
+}
+
+void Diagnostic::setCode(const Diagnostic::Code &code)
+{
+ insertVariant<int, QString>(codeKey, code);
+}
+
+std::optional<WorkspaceEdit::Changes> WorkspaceEdit::changes() const
+{
+ auto it = find(changesKey);
+ if (it == end())
+ return std::nullopt;
+ const QJsonObject &changesObject = it.value().toObject();
+ Changes changesResult;
+ for (const QString &key : changesObject.keys())
+ changesResult[DocumentUri::fromProtocol(key)] = LanguageClientArray<TextEdit>(changesObject.value(key)).toList();
+ return std::make_optional(changesResult);
+}
+
+void WorkspaceEdit::setChanges(const Changes &changes)
+{
+ QJsonObject changesObject;
+ const auto end = changes.end();
+ for (auto it = changes.begin(); it != end; ++it) {
+ QJsonArray edits;
+ for (const TextEdit &edit : it.value())
+ edits.append(QJsonValue(edit));
+ changesObject.insert(QJsonValue(it.key()).toString(), edits);
+ }
+ insert(changesKey, changesObject);
+}
+
+WorkSpaceFolder::WorkSpaceFolder(const DocumentUri &uri, const QString &name)
+{
+ setUri(uri);
+ setName(name);
+}
+
+MarkupOrString::MarkupOrString(const std::variant<QString, MarkupContent> &val)
+ : std::variant<QString, MarkupContent>(val)
+{ }
+
+MarkupOrString::MarkupOrString(const QString &val)
+ : std::variant<QString, MarkupContent>(val)
+{ }
+
+MarkupOrString::MarkupOrString(const MarkupContent &val)
+ : std::variant<QString, MarkupContent>(val)
+{ }
+
+MarkupOrString::MarkupOrString(const QJsonValue &val)
+{
+ if (val.isString()) {
+ emplace<QString>(val.toString());
+ } else {
+ MarkupContent markupContent(val.toObject());
+ if (markupContent.isValid())
+ emplace<MarkupContent>(MarkupContent(val.toObject()));
+ }
+}
+
+QJsonValue MarkupOrString::toJson() const
+{
+ if (std::holds_alternative<QString>(*this))
+ return std::get<QString>(*this);
+ if (std::holds_alternative<MarkupContent>(*this))
+ return QJsonValue(std::get<MarkupContent>(*this));
+ return {};
+}
+
+QMap<QString, QString> languageIds()
+{
+ static const QMap<QString, QString> languages({
+ {"Windows Bat","bat" },
+ {"BibTeX","bibtex" },
+ {"Clojure","clojure" },
+ {"Coffeescript","coffeescript" },
+ {"C","c" },
+ {"C++","cpp" },
+ {"C#","csharp" },
+ {"CSS","css" },
+ {"Diff","diff" },
+ {"Dockerfile","dockerfile" },
+ {"F#","fsharp" },
+ {"Git commit","git-commit" },
+ {"Git rebase","git-rebase" },
+ {"Go","go" },
+ {"Groovy","groovy" },
+ {"Handlebars","handlebars" },
+ {"HTML","html" },
+ {"Ini","ini" },
+ {"Java","java" },
+ {"JavaScript","javascript" },
+ {"JSON","json" },
+ {"LaTeX","latex" },
+ {"Less","less" },
+ {"Lua","lua" },
+ {"Makefile","makefile" },
+ {"Markdown","markdown" },
+ {"Objective-C","objective-c" },
+ {"Objective-C++","objective-cpp" },
+ {"Perl6","perl6" },
+ {"Perl","perl" },
+ {"PHP","php" },
+ {"Powershell","powershell" },
+ {"Pug","jade" },
+ {"Python","python" },
+ {"R","r" },
+ {"Razor (cshtml)","razor" },
+ {"Ruby","ruby" },
+ {"Rust","rust" },
+ {"Scss (syntax using curly brackets)","scss"},
+ {"Sass (indented syntax)","sass" },
+ {"ShaderLab","shaderlab" },
+ {"Shell Script (Bash)","shellscript" },
+ {"SQL","sql" },
+ {"Swift","swift" },
+ {"TypeScript","typescript" },
+ {"TeX","tex" },
+ {"Visual Basic","vb" },
+ {"XML","xml" },
+ {"XSL","xsl" },
+ {"YAML","yaml" }
+ });
+ return languages;
+}
+
+bool TextDocumentItem::isValid() const
+{
+ return contains(uriKey) && contains(languageIdKey) && contains(versionKey) && contains(textKey);
+}
+
+TextDocumentPositionParams::TextDocumentPositionParams()
+ : TextDocumentPositionParams(TextDocumentIdentifier(), Position())
+{
+
+}
+
+TextDocumentPositionParams::TextDocumentPositionParams(
+ const TextDocumentIdentifier &document, const Position &position)
+{
+ setTextDocument(document);
+ setPosition(position);
+}
+
+Position::Position(int line, int character)
+{
+ setLine(line);
+ setCharacter(character);
+}
+
+Range::Range(const Position &start, const Position &end)
+{
+ setStart(start);
+ setEnd(end);
+}
+
+bool Range::contains(const Range &other) const
+{
+ if (start() > other.start())
+ return false;
+ if (end() < other.end())
+ return false;
+ return true;
+}
+
+bool Range::overlaps(const Range &range) const
+{
+ return !isLeftOf(range) && !range.isLeftOf(*this);
+}
+
+QString expressionForGlob(QString globPattern)
+{
+ const QString anySubDir("qtc_anysubdir_id");
+ globPattern.replace("**/", anySubDir);
+ QString regexp = QRegularExpression::wildcardToRegularExpression(globPattern);
+ regexp.replace(anySubDir,"(.*[/\\\\])*");
+ regexp.replace("\\{", "(");
+ regexp.replace("\\}", ")");
+ regexp.replace(",", "|");
+ return regexp;
+}
+
+bool DocumentFilter::applies(const Utils::FilePath &fileName) const
+{
+ if (std::optional<QString> _pattern = pattern()) {
+ QRegularExpression::PatternOption option = QRegularExpression::NoPatternOption;
+ if (fileName.caseSensitivity() == Qt::CaseInsensitive)
+ option = QRegularExpression::CaseInsensitiveOption;
+ const QRegularExpression regexp(expressionForGlob(*_pattern), option);
+ if (regexp.isValid() && regexp.match(fileName.toString()).hasMatch())
+ return true;
+ }
+ // return false when any of the filter didn't match but return true when no filter was defined
+ return !contains(schemeKey) && !contains(languageKey) && !contains(patternKey);
+}
+
+Utils::Link Location::toLink(const DocumentUri::PathMapper &mapToHostPath) const
+{
+ if (!isValid())
+ return Utils::Link();
+
+ return Utils::Link(uri().toFilePath(mapToHostPath),
+ range().start().line() + 1,
+ range().start().character());
+}
+
+// Ensure %xx like %20 are really decoded using fromPercentEncoding
+// Else, a path with spaces would keep its %20 which would cause failure
+// to open the file by the text editor. This is the cases with compilers in
+// C:\Programs Files on Windows.
+DocumentUri::DocumentUri(const QString &other)
+ : QUrl(QUrl::fromPercentEncoding(other.toUtf8()))
+{ }
+
+DocumentUri::DocumentUri(const Utils::FilePath &other, const PathMapper &mapToServerPath)
+ : QUrl(QUrl::fromLocalFile(mapToServerPath(other).path()))
+{ }
+
+Utils::FilePath DocumentUri::toFilePath(const PathMapper &mapToHostPath) const
+{
+ if (isLocalFile()) {
+ const Utils::FilePath serverPath = Utils::FilePath::fromUserInput(toLocalFile());
+ QBS_ASSERT(mapToHostPath, return serverPath);
+ return mapToHostPath(serverPath);
+ }
+ return {};
+}
+
+DocumentUri DocumentUri::fromProtocol(const QString &uri)
+{
+ return DocumentUri(uri);
+}
+
+DocumentUri DocumentUri::fromFilePath(const Utils::FilePath &file, const PathMapper &mapToServerPath)
+{
+ return DocumentUri(file, mapToServerPath);
+}
+
+MarkupKind::MarkupKind(const QJsonValue &value)
+{
+ m_value = value.toString() == "markdown" ? markdown : plaintext;
+}
+
+MarkupKind::operator QJsonValue() const
+{
+ switch (m_value) {
+ case MarkupKind::markdown:
+ return "markdown";
+ case MarkupKind::plaintext:
+ return "plaintext";
+ }
+ return {};
+}
+
+DocumentChange::DocumentChange(const QJsonValue &value)
+{
+ const QString kind = value["kind"].toString();
+ if (kind == "create")
+ emplace<CreateFileOperation>(value);
+ else if (kind == "rename")
+ emplace<RenameFileOperation>(value);
+ else if (kind == "delete")
+ emplace<DeleteFileOperation>(value);
+ else
+ emplace<TextDocumentEdit>(value);
+}
+
+using DocumentChangeBase = std::variant<TextDocumentEdit, CreateFileOperation, RenameFileOperation, DeleteFileOperation>;
+
+bool DocumentChange::isValid() const
+{
+ return std::visit([](const auto &v) { return v.isValid(); }, DocumentChangeBase(*this));
+}
+
+DocumentChange::operator const QJsonValue () const
+{
+ return std::visit([](const auto &v) { return QJsonValue(v); }, DocumentChangeBase(*this));
+}
+
+CreateFileOperation::CreateFileOperation()
+{
+ insert(kindKey, "create");
+}
+
+QString CreateFileOperation::message(const DocumentUri::PathMapper &mapToHostPath) const
+{
+ return Tr::tr("Create %1").arg(uri().toFilePath(mapToHostPath).toUserOutput());
+}
+
+bool CreateFileOperation::isValid() const
+{
+ return contains(uriKey) && value(kindKey) == "create";
+}
+
+RenameFileOperation::RenameFileOperation()
+{
+ insert(kindKey, "rename");
+}
+
+QString RenameFileOperation::message(const DocumentUri::PathMapper &mapToHostPath) const
+{
+ return Tr::tr("Rename %1 to %2")
+ .arg(oldUri().toFilePath(mapToHostPath).toUserOutput(),
+ newUri().toFilePath(mapToHostPath).toUserOutput());
+}
+
+bool RenameFileOperation::isValid() const
+{
+ return contains(oldUriKey) && contains(newUriKey) && value(kindKey) == "rename";
+}
+
+DeleteFileOperation::DeleteFileOperation()
+{
+ insert(kindKey, "delete");
+}
+
+QString DeleteFileOperation::message(const DocumentUri::PathMapper &mapToHostPath) const
+{
+ return Tr::tr("Delete %1").arg(uri().toFilePath(mapToHostPath).toUserOutput());
+}
+
+bool DeleteFileOperation::isValid() const
+{
+ return contains(uriKey) && value(kindKey) == "delete";
+}
+
+} // namespace lsp
diff --git a/src/shared/lsp/lsptypes.h b/src/shared/lsp/lsptypes.h
new file mode 100644
index 000000000..52e7b95a9
--- /dev/null
+++ b/src/shared/lsp/lsptypes.h
@@ -0,0 +1,680 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "jsonkeys.h"
+#include "jsonobject.h"
+#include "lsputils.h"
+#include "filepath.h"
+#include "link.h"
+
+#include <QJsonObject>
+#include <QUrl>
+#include <QList>
+
+#include <optional>
+#include <variant>
+
+namespace lsp {
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentUri : public QUrl
+{
+public:
+ DocumentUri() = default;
+ using PathMapper = std::function<Utils::FilePath(const Utils::FilePath &)>;
+ Utils::FilePath toFilePath(const PathMapper &mapToHostPath) const;
+
+ static DocumentUri fromProtocol(const QString &uri);
+ static DocumentUri fromFilePath(const Utils::FilePath &file, const PathMapper &mapToServerPath);
+
+ operator QJsonValue() const { return QJsonValue(toString()); }
+
+private:
+ DocumentUri(const QString &other);
+ DocumentUri(const Utils::FilePath &other, const PathMapper &mapToServerPath);
+
+ friend class LanguageClientValue<QString>;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT Position : public JsonObject
+{
+public:
+ Position() = default;
+ Position(int line, int character);
+ using JsonObject::JsonObject;
+
+ // Line position in a document (zero-based).
+ int line() const { return typedValue<int>(lineKey); }
+ void setLine(int line) { insert(lineKey, line); }
+
+ /*
+ * Character offset on a line in a document (zero-based). Assuming that the line is
+ * represented as a string, the `character` value represents the gap between the
+ * `character` and `character + 1`.
+ *
+ * If the character value is greater than the line length it defaults back to the
+ * line length.
+ */
+ int character() const { return typedValue<int>(characterKey); }
+ void setCharacter(int character) { insert(characterKey, character); }
+
+ bool isValid() const override
+ { return contains(lineKey) && contains(characterKey); }
+};
+
+inline bool operator<(const Position &first, const Position &second)
+{
+ return first.line() < second.line()
+ || (first.line() == second.line() && first.character() < second.character());
+}
+
+inline bool operator>(const Position &first, const Position &second)
+{
+ return second < first;
+}
+
+inline bool operator>=(const Position &first, const Position &second)
+{
+ return !(first < second);
+}
+
+inline bool operator<=(const Position &first, const Position &second)
+{
+ return !(first > second);
+}
+
+class LANGUAGESERVERPROTOCOL_EXPORT Range : public JsonObject
+{
+public:
+ Range() = default;
+ Range(const Position &start, const Position &end);
+ using JsonObject::JsonObject;
+
+ // The range's start position.
+ Position start() const { return typedValue<Position>(startKey); }
+ void setStart(const Position &start) { insert(startKey, start); }
+
+ // The range's end position.
+ Position end() const { return typedValue<Position>(endKey); }
+ void setEnd(const Position &end) { insert(endKey, end); }
+
+ bool isEmpty() const { return start() == end(); }
+ bool contains(const Position &pos) const { return start() <= pos && pos <= end(); }
+ bool contains(const Range &other) const;
+ bool overlaps(const Range &range) const;
+ bool isLeftOf(const Range &other) const
+ { return isEmpty() || other.isEmpty() ? end() < other.start() : end() <= other.start(); }
+
+ bool isValid() const override
+ { return JsonObject::contains(startKey) && JsonObject::contains(endKey); }
+};
+
+inline bool operator==(const Range &r1, const Range &r2)
+{
+ return r1.contains(r2) && r2.contains(r1);
+}
+inline bool operator!=(const Range &r1, const Range &r2) { return !(r1 == r2); }
+
+class LANGUAGESERVERPROTOCOL_EXPORT Location : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ DocumentUri uri() const { return DocumentUri::fromProtocol(typedValue<QString>(uriKey)); }
+ void setUri(const DocumentUri &uri) { insert(uriKey, uri); }
+
+ Range range() const { return typedValue<Range>(rangeKey); }
+ void setRange(const Range &range) { insert(rangeKey, range); }
+
+ Utils::Link toLink(const DocumentUri::PathMapper &mapToHostPath) const;
+
+ bool isValid() const override { return contains(uriKey) && contains(rangeKey); }
+};
+
+enum class DiagnosticSeverity
+{
+ Error = 1,
+ Warning = 2,
+ Information = 3,
+ Hint = 4
+
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT Diagnostic : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ // The range at which the message applies.
+ Range range() const { return typedValue<Range>(rangeKey); }
+ void setRange(const Range &range) { insert(rangeKey, range); }
+
+ // The diagnostic's severity. Can be omitted. If omitted it is up to the
+ // client to interpret diagnostics as error, warning, info or hint.
+ std::optional<DiagnosticSeverity> severity() const;
+ void setSeverity(const DiagnosticSeverity &severity)
+ { insert(severityKey, static_cast<int>(severity)); }
+ void clearSeverity() { remove(severityKey); }
+
+ // The diagnostic's code, which might appear in the user interface.
+ using Code = std::variant<int, QString>;
+ std::optional<Code> code() const;
+ void setCode(const Code &code);
+ void clearCode() { remove(codeKey); }
+
+ // A human-readable string describing the source of this
+ // diagnostic, e.g. 'typescript' or 'super lint'.
+ std::optional<QString> source() const
+ { return optionalValue<QString>(sourceKey); }
+ void setSource(const QString &source) { insert(sourceKey, source); }
+ void clearSource() { remove(sourceKey); }
+
+ // The diagnostic's message.
+ QString message() const
+ { return typedValue<QString>(messageKey); }
+ void setMessage(const QString &message) { insert(messageKey, message); }
+
+ bool isValid() const override { return contains(rangeKey) && contains(messageKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT Command : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ // Title of the command, like `save`.
+ QString title() const { return typedValue<QString>(titleKey); }
+ void setTitle(const QString &title) { insert(titleKey, title); }
+ void clearTitle() { remove(titleKey); }
+
+ // The identifier of the actual command handler.
+ QString command() const { return typedValue<QString>(commandKey); }
+ void setCommand(const QString &command) { insert(commandKey, command); }
+ void clearCommand() { remove(commandKey); }
+
+ // Arguments that the command handler should be invoked with.
+ std::optional<QJsonArray> arguments() const { return typedValue<QJsonArray>(argumentsKey); }
+ void setArguments(const QJsonArray &arguments) { insert(argumentsKey, arguments); }
+ void clearArguments() { remove(argumentsKey); }
+
+ bool isValid() const override { return contains(titleKey) && contains(commandKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT TextEdit : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ // The range of the text document to be manipulated. To insert
+ // text into a document create a range where start === end.
+ Range range() const { return typedValue<Range>(rangeKey); }
+ void setRange(const Range &range) { insert(rangeKey, range); }
+
+ // The string to be inserted. For delete operations use an empty string.
+ QString newText() const { return typedValue<QString>(newTextKey); }
+ void setNewText(const QString &text) { insert(newTextKey, text); }
+
+ bool isValid() const override
+ { return contains(rangeKey) && contains(newTextKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentIdentifier : public JsonObject
+{
+public:
+ TextDocumentIdentifier() : TextDocumentIdentifier(DocumentUri()) {}
+ explicit TextDocumentIdentifier(const DocumentUri &uri) { setUri(uri); }
+ using JsonObject::JsonObject;
+
+ // The text document's URI.
+ DocumentUri uri() const { return DocumentUri::fromProtocol(typedValue<QString>(uriKey)); }
+ void setUri(const DocumentUri &uri) { insert(uriKey, uri); }
+
+ bool isValid() const override { return contains(uriKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT VersionedTextDocumentIdentifier : public TextDocumentIdentifier
+{
+public:
+ using TextDocumentIdentifier::TextDocumentIdentifier;
+
+ /*
+ * The version number of this document. If a versioned text document identifier
+ * is sent from the server to the client and the file is not open in the editor
+ * (the server has not received an open notification before) the server can send
+ * `null` to indicate that the version is known and the content on disk is the
+ * truth (as speced with document content ownership)
+ */
+ LanguageClientValue<int> version() const { return clientValue<int>(versionKey); }
+ void setVersion(LanguageClientValue<int> version) { insert(versionKey, version); }
+
+ bool isValid() const override
+ {
+ return TextDocumentIdentifier::isValid() && contains(versionKey);
+ }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentEdit : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ // The text document to change.
+ VersionedTextDocumentIdentifier textDocument() const
+ { return typedValue<VersionedTextDocumentIdentifier>(textDocumentKey); }
+ void setTextDocument(const VersionedTextDocumentIdentifier &textDocument)
+ { insert(textDocumentKey, textDocument); }
+
+ // The edits to be applied.
+ QList<TextEdit> edits() const { return array<TextEdit>(editsKey); }
+ void setEdits(const QList<TextEdit> edits) { insertArray(editsKey, edits); }
+
+ bool isValid() const override { return contains(textDocumentKey) && contains(editsKey); }
+};
+
+class CreateFileOptions : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ std::optional<bool> overwrite() const { return optionalValue<bool>(overwriteKey); }
+ void setOverwrite(bool overwrite) { insert(overwriteKey, overwrite); }
+ void clearOverwrite() { remove(overwriteKey); }
+
+ std::optional<bool> ignoreIfExists() const { return optionalValue<bool>(ignoreIfExistsKey); }
+ void setIgnoreIfExists(bool ignoreIfExists) { insert(ignoreIfExistsKey, ignoreIfExists); }
+ void clearIgnoreIfExists() { remove(ignoreIfExistsKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT CreateFileOperation : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+ CreateFileOperation();
+
+ DocumentUri uri() const { return DocumentUri::fromProtocol(typedValue<QString>(uriKey)); }
+ void setUri(const DocumentUri &uri) { insert(uriKey, uri); }
+
+ std::optional<CreateFileOptions> options() const
+ { return optionalValue<CreateFileOptions>(optionsKey); }
+ void setOptions(const CreateFileOptions &options) { insert(optionsKey, options); }
+ void clearOptions() { remove(optionsKey); }
+
+ QString message(const DocumentUri::PathMapper &mapToHostPath) const;
+
+ bool isValid() const override;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT RenameFileOperation : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+ RenameFileOperation();
+
+ DocumentUri oldUri() const { return DocumentUri::fromProtocol(typedValue<QString>(oldUriKey)); }
+ void setOldUri(const DocumentUri &oldUri) { insert(oldUriKey, oldUri); }
+
+ DocumentUri newUri() const { return DocumentUri::fromProtocol(typedValue<QString>(newUriKey)); }
+ void setNewUri(const DocumentUri &newUri) { insert(newUriKey, newUri); }
+
+ std::optional<CreateFileOptions> options() const
+ { return optionalValue<CreateFileOptions>(optionsKey); }
+ void setOptions(const CreateFileOptions &options) { insert(optionsKey, options); }
+ void clearOptions() { remove(optionsKey); }
+
+ QString message(const DocumentUri::PathMapper &mapToHostPath) const;
+
+ bool isValid() const override;
+};
+
+class DeleteFileOptions : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ std::optional<bool> recursive() const { return optionalValue<bool>(recursiveKey); }
+ void setRecursive(bool recursive) { insert(recursiveKey, recursive); }
+ void clearRecursive() { remove(recursiveKey); }
+
+ std::optional<bool> ignoreIfNotExists() const { return optionalValue<bool>(ignoreIfNotExistsKey); }
+ void setIgnoreIfNotExists(bool ignoreIfNotExists) { insert(ignoreIfNotExistsKey, ignoreIfNotExists); }
+ void clearIgnoreIfNotExists() { remove(ignoreIfNotExistsKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DeleteFileOperation : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+ DeleteFileOperation();
+
+ DocumentUri uri() const { return DocumentUri::fromProtocol(typedValue<QString>(uriKey)); }
+ void setUri(const DocumentUri &uri) { insert(uriKey, uri); }
+
+ std::optional<DeleteFileOptions> options() const
+ { return optionalValue<DeleteFileOptions>(optionsKey); }
+ void setOptions(const DeleteFileOptions &options) { insert(optionsKey, options); }
+ void clearOptions() { remove(optionsKey); }
+
+ QString message(const DocumentUri::PathMapper &mapToHostPath) const;
+
+ bool isValid() const override;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentChange
+ : public std::variant<TextDocumentEdit, CreateFileOperation, RenameFileOperation, DeleteFileOperation>
+{
+public:
+ using variant::variant;
+ DocumentChange(const QJsonValue &value);
+
+ bool isValid() const;
+
+ operator const QJsonValue() const;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkspaceEdit : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ // Holds changes to existing resources.
+ using Changes = QMap<DocumentUri, QList<TextEdit>>;
+ std::optional<Changes> changes() const;
+ void setChanges(const Changes &changes);
+
+ /*
+ * Depending on the client capability
+ * `workspace.workspaceEdit.resourceOperations` document changes are either
+ * an array of `TextDocumentEdit`s to express changes to n different text
+ * documents where each text document edit addresses a specific version of
+ * a text document. Or it can contain above `TextDocumentEdit`s mixed with
+ * create, rename and delete file / folder operations.
+ *
+ * Whether a client supports versioned document edits is expressed via
+ * `workspace.workspaceEdit.documentChanges` client capability.
+ *
+ * If a client neither supports `documentChanges` nor
+ * `workspace.workspaceEdit.resourceOperations` then only plain `TextEdit`s
+ * using the `changes` property are supported.
+ */
+ std::optional<QList<DocumentChange>> documentChanges() const
+ { return optionalArray<DocumentChange>(documentChangesKey); }
+ void setDocumentChanges(const QList<DocumentChange> &changes)
+ { insertArray(documentChangesKey, changes); }
+};
+
+LANGUAGESERVERPROTOCOL_EXPORT QMap<QString, QString> languageIds();
+
+class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentItem : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ // The text document's URI.
+ DocumentUri uri() const { return DocumentUri::fromProtocol(typedValue<QString>(uriKey)); }
+ void setUri(const DocumentUri &uri) { insert(uriKey, uri); }
+
+ // The text document's language identifier.
+ QString languageId() const { return typedValue<QString>(languageIdKey); }
+ void setLanguageId(const QString &id) { insert(languageIdKey, id); }
+
+ // The version number of this document (it will increase after each change, including undo/redo
+ int version() const { return typedValue<int>(versionKey); }
+ void setVersion(int version) { insert(versionKey, version); }
+
+ // The content of the opened text document.
+ QString text() const { return typedValue<QString>(textKey); }
+ void setText(const QString &text) { insert(textKey, text); }
+
+ bool isValid() const override;
+
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentPositionParams : public JsonObject
+{
+public:
+ TextDocumentPositionParams();
+ TextDocumentPositionParams(const TextDocumentIdentifier &document, const Position &position);
+ using JsonObject::JsonObject;
+
+ // The text document.
+ TextDocumentIdentifier textDocument() const
+ { return typedValue<TextDocumentIdentifier>(textDocumentKey); }
+ void setTextDocument(const TextDocumentIdentifier &id) { insert(textDocumentKey, id); }
+
+ // The position inside the text document.
+ Position position() const { return typedValue<Position>(positionKey); }
+ void setPosition(const Position &position) { insert(positionKey, position); }
+
+ bool isValid() const override { return contains(textDocumentKey) && contains(positionKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentFilter : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ // A language id, like `typescript`.
+ std::optional<QString> language() const { return optionalValue<QString>(languageKey); }
+ void setLanguage(const QString &language) { insert(languageKey, language); }
+ void clearLanguage() { remove(languageKey); }
+
+ // A Uri [scheme](#Uri.scheme), like `file` or `untitled`.
+ std::optional<QString> scheme() const { return optionalValue<QString>(schemeKey); }
+ void setScheme(const QString &scheme) { insert(schemeKey, scheme); }
+ void clearScheme() { remove(schemeKey); }
+
+ /**
+ * A glob pattern, like `*.{ts,js}`.
+ *
+ * Glob patterns can have the following syntax:
+ * - `*` to match one or more characters in a path segment
+ * - `?` to match on one character in a path segment
+ * - `**` to match any number of path segments, including none
+ * - `{}` to group sub patterns into an OR expression. (e.g. `*.{ts,js}`
+ * matches all TypeScript and JavaScript files)
+ * - `[]` to declare a range of characters to match in a path segment
+ * (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …)
+ * - `[!...]` to negate a range of characters to match in a path segment
+ * (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but
+ * not `example.0`)
+ */
+ std::optional<QString> pattern() const { return optionalValue<QString>(patternKey); }
+ void setPattern(const QString &pattern) { insert(patternKey, pattern); }
+ void clearPattern() { remove(patternKey); }
+
+ bool applies(const Utils::FilePath &fileName) const;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT MarkupKind
+{
+public:
+ enum Value { plaintext, markdown };
+ MarkupKind() = default;
+ MarkupKind(const Value value)
+ : m_value(value)
+ {}
+ explicit MarkupKind(const QJsonValue &value);
+
+ operator QJsonValue() const;
+ Value value() const { return m_value; }
+
+ bool operator==(const Value &value) const { return m_value == value; }
+
+ bool isValid() const { return true; }
+private:
+ Value m_value = plaintext;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT MarkupContent : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ // The type of the Markup
+ MarkupKind kind() const { return MarkupKind(value(kindKey)); }
+ void setKind(MarkupKind kind) { insert(kindKey, kind); }
+ Qt::TextFormat textFormat() const
+ { return kind() == MarkupKind::markdown ? Qt::MarkdownText : Qt::PlainText; }
+
+ // The content itself
+ QString content() const { return typedValue<QString>(contentKey); }
+ void setContent(const QString &content) { insert(contentKey, content); }
+
+ bool isValid() const override
+ { return contains(kindKey) && contains(contentKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT MarkupOrString : public std::variant<QString, MarkupContent>
+{
+public:
+ MarkupOrString() = default;
+ explicit MarkupOrString(const std::variant<QString, MarkupContent> &val);
+ explicit MarkupOrString(const QString &val);
+ explicit MarkupOrString(const MarkupContent &val);
+ MarkupOrString(const QJsonValue &val);
+
+ bool isValid() const { return true; }
+
+ QJsonValue toJson() const;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkSpaceFolder : public JsonObject
+{
+public:
+ WorkSpaceFolder() = default;
+ WorkSpaceFolder(const DocumentUri &uri, const QString &name);
+ using JsonObject::JsonObject;
+
+ // The associated URI for this workspace folder.
+ DocumentUri uri() const { return DocumentUri::fromProtocol(typedValue<QString>(uriKey)); }
+ void setUri(const DocumentUri &uri) { insert(uriKey, uri); }
+
+ // The name of the workspace folder. Defaults to the uri's basename.
+ QString name() const { return typedValue<QString>(nameKey); }
+ void setName(const QString &name) { insert(nameKey, name); }
+
+ bool isValid() const override
+ { return contains(uriKey) && contains(nameKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SymbolInformation : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ QString name() const { return typedValue<QString>(nameKey); }
+ void setName(const QString &name) { insert(nameKey, name); }
+
+ int kind() const { return typedValue<int>(kindKey); }
+ void setKind(int kind) { insert(kindKey, kind); }
+
+ std::optional<bool> deprecated() const { return optionalValue<bool>(deprecatedKey); }
+ void setDeprecated(bool deprecated) { insert(deprecatedKey, deprecated); }
+ void clearDeprecated() { remove(deprecatedKey); }
+
+ Location location() const { return typedValue<Location>(locationKey); }
+ void setLocation(const Location &location) { insert(locationKey, location); }
+
+ std::optional<QString> containerName() const
+ { return optionalValue<QString>(containerNameKey); }
+ void setContainerName(const QString &containerName) { insert(containerNameKey, containerName); }
+ void clearContainerName() { remove(containerNameKey); }
+
+ bool isValid() const override
+ { return contains(nameKey) && contains(kindKey) && contains(locationKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DocumentSymbol : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ QString name() const { return typedValue<QString>(nameKey); }
+ void setName(const QString &name) { insert(nameKey, name); }
+
+ std::optional<QString> detail() const { return optionalValue<QString>(detailKey); }
+ void setDetail(const QString &detail) { insert(detailKey, detail); }
+ void clearDetail() { remove(detailKey); }
+
+ int kind() const { return typedValue<int>(kindKey); }
+ void setKind(int kind) { insert(kindKey, kind); }
+
+ std::optional<bool> deprecated() const { return optionalValue<bool>(deprecatedKey); }
+ void setDeprecated(bool deprecated) { insert(deprecatedKey, deprecated); }
+ void clearDeprecated() { remove(deprecatedKey); }
+
+ Range range() const { return typedValue<Range>(rangeKey); }
+ void setRange(Range range) { insert(rangeKey, range); }
+
+ Range selectionRange() const { return typedValue<Range>(selectionRangeKey); }
+ void setSelectionRange(Range selectionRange) { insert(selectionRangeKey, selectionRange); }
+
+ std::optional<QList<DocumentSymbol>> children() const
+ { return optionalArray<DocumentSymbol>(childrenKey); }
+ void setChildren(QList<DocumentSymbol> children) { insertArray(childrenKey, children); }
+ void clearChildren() { remove(childrenKey); }
+};
+
+enum class SymbolKind {
+ File = 1,
+ FirstSymbolKind = File,
+ Module = 2,
+ Namespace = 3,
+ Package = 4,
+ Class = 5,
+ Method = 6,
+ Property = 7,
+ Field = 8,
+ Constructor = 9,
+ Enum = 10,
+ Interface = 11,
+ Function = 12,
+ Variable = 13,
+ Constant = 14,
+ String = 15,
+ Number = 16,
+ Boolean = 17,
+ Array = 18,
+ Object = 19,
+ Key = 20,
+ Null = 21,
+ EnumMember = 22,
+ Struct = 23,
+ Event = 24,
+ Operator = 25,
+ TypeParameter = 26,
+ LastSymbolKind = TypeParameter,
+};
+
+namespace CompletionItemKind {
+enum Kind {
+ Text = 1,
+ Method = 2,
+ Function = 3,
+ Constructor = 4,
+ Field = 5,
+ Variable = 6,
+ Class = 7,
+ Interface = 8,
+ Module = 9,
+ Property = 10,
+ Unit = 11,
+ Value = 12,
+ Enum = 13,
+ Keyword = 14,
+ Snippet = 15,
+ Color = 16,
+ File = 17,
+ Reference = 18,
+ Folder = 19,
+ EnumMember = 20,
+ Constant = 21,
+ Struct = 22,
+ Event = 23,
+ Operator = 24,
+ TypeParameter = 25
+};
+} // namespace CompletionItemKind
+
+} // namespace LanguageClient
diff --git a/src/shared/lsp/lsputils.cpp b/src/shared/lsp/lsputils.cpp
new file mode 100644
index 000000000..f26a8a21c
--- /dev/null
+++ b/src/shared/lsp/lsputils.cpp
@@ -0,0 +1,68 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "lsputils.h"
+
+#include <QHash>
+#include <QLoggingCategory>
+#include <QVector>
+
+namespace lsp {
+
+Q_LOGGING_CATEGORY(conversionLog, "qtc.languageserverprotocol.conversion", QtWarningMsg)
+
+template<>
+QString fromJsonValue<QString>(const QJsonValue &value)
+{
+ if (conversionLog().isDebugEnabled() && !value.isString())
+ qCDebug(conversionLog) << "Expected String in json value but got: " << value;
+ return value.toString();
+}
+
+template<>
+int fromJsonValue<int>(const QJsonValue &value)
+{
+ if (conversionLog().isDebugEnabled() && !value.isDouble())
+ qCDebug(conversionLog) << "Expected double in json value but got: " << value;
+ return value.toInt();
+}
+
+template<>
+double fromJsonValue<double>(const QJsonValue &value)
+{
+ if (conversionLog().isDebugEnabled() && !value.isDouble())
+ qCDebug(conversionLog) << "Expected double in json value but got: " << value;
+ return value.toDouble();
+}
+
+template<>
+bool fromJsonValue<bool>(const QJsonValue &value)
+{
+ if (conversionLog().isDebugEnabled() && !value.isBool())
+ qCDebug(conversionLog) << "Expected bool in json value but got: " << value;
+ return value.toBool();
+}
+
+template<>
+QJsonArray fromJsonValue<QJsonArray>(const QJsonValue &value)
+{
+ if (conversionLog().isDebugEnabled() && !value.isArray())
+ qCDebug(conversionLog) << "Expected Array in json value but got: " << value;
+ return value.toArray();
+}
+
+template<>
+QJsonObject fromJsonValue<QJsonObject>(const QJsonValue &value)
+{
+ if (conversionLog().isDebugEnabled() && !value.isObject())
+ qCDebug(conversionLog) << "Expected Object in json value but got: " << value;
+ return value.toObject();
+}
+
+template<>
+QJsonValue fromJsonValue<QJsonValue>(const QJsonValue &value)
+{
+ return value;
+}
+
+} // namespace lsp
diff --git a/src/shared/lsp/lsputils.h b/src/shared/lsp/lsputils.h
new file mode 100644
index 000000000..eb7a18342
--- /dev/null
+++ b/src/shared/lsp/lsputils.h
@@ -0,0 +1,160 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "languageserverprotocol_global.h"
+
+#include <tools/qbsassert.h>
+
+#include <QJsonArray>
+#include <QJsonObject>
+#include <QLoggingCategory>
+
+#include <variant>
+
+namespace lsp {
+
+LANGUAGESERVERPROTOCOL_EXPORT Q_DECLARE_LOGGING_CATEGORY(conversionLog)
+
+template <typename T>
+T fromJsonValue(const QJsonValue &value)
+{
+ if (conversionLog().isDebugEnabled() && !value.isObject())
+ qCDebug(conversionLog) << "Expected Object in json value but got: " << value;
+ T result(value.toObject());
+ if (conversionLog().isDebugEnabled() && !result.isValid())
+ qCDebug(conversionLog) << typeid(result).name() << " is not valid: " << result;
+ return result;
+}
+
+template<>
+LANGUAGESERVERPROTOCOL_EXPORT QString fromJsonValue<QString>(const QJsonValue &value);
+
+template<>
+LANGUAGESERVERPROTOCOL_EXPORT int fromJsonValue<int>(const QJsonValue &value);
+
+template<>
+LANGUAGESERVERPROTOCOL_EXPORT double fromJsonValue<double>(const QJsonValue &value);
+
+template<>
+LANGUAGESERVERPROTOCOL_EXPORT bool fromJsonValue<bool>(const QJsonValue &value);
+
+template<>
+LANGUAGESERVERPROTOCOL_EXPORT QJsonObject fromJsonValue<QJsonObject>(const QJsonValue &value);
+
+template<>
+LANGUAGESERVERPROTOCOL_EXPORT QJsonArray fromJsonValue<QJsonArray>(const QJsonValue &value);
+
+template<>
+LANGUAGESERVERPROTOCOL_EXPORT QJsonValue fromJsonValue<QJsonValue>(const QJsonValue &value);
+
+template <typename T>
+class LanguageClientArray : public std::variant<QList<T>, std::nullptr_t>
+{
+public:
+ using std::variant<QList<T>, std::nullptr_t>::variant;
+ using std::variant<QList<T>, std::nullptr_t>::operator=;
+
+ LanguageClientArray() {}
+
+ explicit LanguageClientArray(const QList<T> &list)
+ { *this = list; }
+
+ explicit LanguageClientArray(const QJsonValue &value)
+ {
+ if (value.isArray()) {
+ QList<T> values;
+ values.reserve(value.toArray().count());
+ for (auto arrayValue : value.toArray())
+ values << fromJsonValue<T>(arrayValue);
+ *this = values;
+ } else {
+ *this = nullptr;
+ }
+ }
+
+ QJsonValue toJson() const
+ {
+ if (const auto list = std::get_if<QList<T>>(this)) {
+ QJsonArray array;
+ for (const T &value : *list)
+ array.append(QJsonValue(value));
+ return array;
+ }
+ return QJsonValue();
+ }
+
+ QList<T> toListOrEmpty() const
+ {
+ if (std::holds_alternative<QList<T>>(*this))
+ return std::get<QList<T>>(*this);
+ return {};
+ }
+
+ QList<T> toList() const
+ {
+ QBS_ASSERT(std::holds_alternative<QList<T>>(*this), return {});
+ return std::get<QList<T>>(*this);
+ }
+ bool isNull() const { return std::holds_alternative<std::nullptr_t>(*this); }
+};
+
+template <typename T>
+class LanguageClientValue : public std::variant<T, std::nullptr_t>
+{
+public:
+ using std::variant<T, std::nullptr_t>::operator=;
+
+ LanguageClientValue() : std::variant<T, std::nullptr_t>(nullptr) { }
+ LanguageClientValue(const T &value) : std::variant<T, std::nullptr_t>(value) { }
+ LanguageClientValue(const QJsonValue &value)
+ {
+ if (!QBS_GUARD(!value.isUndefined()) || value.isNull())
+ *this = nullptr;
+ else
+ *this = fromJsonValue<T>(value);
+ }
+
+ operator const QJsonValue() const
+ {
+ if (auto val = std::get_if<T>(this))
+ return QJsonValue(*val);
+ return QJsonValue();
+ }
+
+ T value(const T &defaultValue = T()) const
+ {
+ QBS_ASSERT(std::holds_alternative<T>(*this), return defaultValue);
+ return std::get<T>(*this);
+ }
+
+ template<typename Type>
+ LanguageClientValue<Type> transform()
+ {
+ QBS_ASSERT(!std::holds_alternative<T>(*this), return LanguageClientValue<Type>());
+ return Type(std::get<T>(*this));
+ }
+
+ bool isNull() const { return std::holds_alternative<std::nullptr_t>(*this); }
+};
+
+template <typename T>
+QJsonArray enumArrayToJsonArray(const QList<T> &values)
+{
+ QJsonArray array;
+ for (T value : values)
+ array.append(static_cast<int>(value));
+ return array;
+}
+
+template <typename T>
+QList<T> jsonArrayToList(const QJsonArray &array)
+{
+ QList<T> list;
+ for (const QJsonValue &val : array)
+ list << fromJsonValue<T>(val);
+ return list;
+}
+
+} // namespace lsp
diff --git a/src/shared/lsp/messages.cpp b/src/shared/lsp/messages.cpp
new file mode 100644
index 000000000..a909fdb82
--- /dev/null
+++ b/src/shared/lsp/messages.cpp
@@ -0,0 +1,45 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "messages.h"
+
+namespace lsp {
+
+constexpr const char ShowMessageNotification::methodName[];
+constexpr const char ShowMessageRequest::methodName[];
+constexpr const char LogMessageNotification::methodName[];
+constexpr const char TelemetryNotification::methodName[];
+
+ShowMessageNotification::ShowMessageNotification(const ShowMessageParams &params)
+ : Notification(methodName, params)
+{ }
+
+ShowMessageRequest::ShowMessageRequest(const ShowMessageRequestParams &params)
+ : Request(methodName, params)
+{ }
+
+LogMessageNotification::LogMessageNotification(const LogMessageParams &params)
+ : Notification(methodName, params)
+{ }
+
+TelemetryNotification::TelemetryNotification(const JsonObject &params)
+ : Notification(methodName, params)
+{ }
+
+static QString messageTypeName(int messageType)
+{
+ switch (messageType) {
+ case Error: return QString("Error");
+ case Warning: return QString("Warning");
+ case Info: return QString("Info");
+ case Log: return QString("Log");
+ }
+ return QString("");
+}
+
+QString ShowMessageParams::toString() const
+{
+ return messageTypeName(type()) + ": " + message();
+}
+
+} // namespace lsp
diff --git a/src/shared/lsp/messages.h b/src/shared/lsp/messages.h
new file mode 100644
index 000000000..8c7d05c6d
--- /dev/null
+++ b/src/shared/lsp/messages.h
@@ -0,0 +1,93 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "jsonrpcmessages.h"
+
+namespace lsp {
+
+enum MessageType {
+ Error = 1,
+ Warning = 2,
+ Info = 3,
+ Log = 4,
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ShowMessageParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ int type() const { return typedValue<int>(typeKey); }
+ void setType(int type) { insert(typeKey, type); }
+
+ QString message() const { return typedValue<QString>(messageKey); }
+ void setMessage(QString message) { insert(messageKey, message); }
+
+ QString toString() const;
+
+ bool isValid() const override
+ { return contains(typeKey) && contains(messageKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ShowMessageNotification : public Notification<ShowMessageParams>
+{
+public:
+ explicit ShowMessageNotification(const ShowMessageParams &params);
+ using Notification::Notification;
+ constexpr static const char methodName[] = "window/showMessage";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT MessageActionItem : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ QString title() const { return typedValue<QString>(titleKey); }
+ void setTitle(QString title) { insert(titleKey, title); }
+
+ bool isValid() const override { return contains(titleKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ShowMessageRequestParams : public ShowMessageParams
+{
+public:
+ using ShowMessageParams::ShowMessageParams;
+
+ std::optional<QList<MessageActionItem>> actions() const
+ { return optionalArray<MessageActionItem>(actionsKey); }
+ void setActions(const QList<MessageActionItem> &actions) { insertArray(actionsKey, actions); }
+ void clearActions() { remove(actionsKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ShowMessageRequest : public Request<
+ LanguageClientValue<MessageActionItem>, std::nullptr_t, ShowMessageRequestParams>
+{
+public:
+ explicit ShowMessageRequest(const ShowMessageRequestParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "window/showMessageRequest";
+};
+
+using LogMessageParams = ShowMessageParams;
+
+class LANGUAGESERVERPROTOCOL_EXPORT LogMessageNotification : public Notification<LogMessageParams>
+{
+public:
+ explicit LogMessageNotification(const LogMessageParams &params);
+ using Notification::Notification;
+ constexpr static const char methodName[] = "window/logMessage";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT TelemetryNotification : public Notification<JsonObject>
+{
+public:
+ explicit TelemetryNotification(const JsonObject &params);
+ using Notification::Notification;
+ constexpr static const char methodName[] = "telemetry/event";
+
+ bool parametersAreValid(QString * /*error*/) const override { return params().has_value(); }
+};
+
+} // namespace LanguageClient
diff --git a/src/shared/lsp/predicates.h b/src/shared/lsp/predicates.h
new file mode 100644
index 000000000..800a84757
--- /dev/null
+++ b/src/shared/lsp/predicates.h
@@ -0,0 +1,110 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+namespace lsp::Utils
+{
+
+//////////////////
+// find helpers
+//////////////////
+template<typename R, typename S, typename T>
+decltype(auto) equal(R (S::*function)() const, T value)
+{
+ // This should use std::equal_to<> instead of std::equal_to<T>,
+ // but that's not supported everywhere yet, since it is C++14
+ return std::bind<bool>(std::equal_to<T>(), value, std::bind(function, std::placeholders::_1));
+}
+
+template<typename R, typename S, typename T>
+decltype(auto) equal(R S::*member, T value)
+{
+ return std::bind<bool>(std::equal_to<T>(), value, std::bind(member, std::placeholders::_1));
+}
+
+//////////////////
+// comparison predicates
+//////////////////
+template <typename Type>
+auto equalTo(Type &&value)
+{
+ return [value = std::forward<Type>(value)] (const auto &entry)
+ {
+ static_assert(std::is_same<std::decay_t<Type>,
+ std::decay_t<decltype(entry)>>::value,
+ "The container and predicate type of equalTo should be the same to prevent "
+ "unnecessary conversion.");
+ return entry == value;
+ };
+}
+
+template <typename Type>
+auto unequalTo(Type &&value)
+{
+ return [value = std::forward<Type>(value)] (const auto &entry)
+ {
+ static_assert(std::is_same<std::decay_t<Type>,
+ std::decay_t<decltype(entry)>>::value,
+ "The container and predicate type of unequalTo should be the same to prevent "
+ "unnecessary conversion.");
+ return !(entry == value);
+ };
+}
+
+template <typename Type>
+auto lessThan(Type &&value)
+{
+ return [value = std::forward<Type>(value)] (const auto &entry)
+ {
+ static_assert(std::is_same<std::decay_t<Type>,
+ std::decay_t<decltype(entry)>>::value,
+ "The container and predicate type of unequalTo should be the same to prevent "
+ "unnecessary conversion.");
+ return entry < value;
+ };
+}
+
+template <typename Type>
+auto lessEqualThan(Type &&value)
+{
+ return [value = std::forward<Type>(value)] (const auto &entry)
+ {
+ static_assert(std::is_same<std::decay_t<Type>,
+ std::decay_t<decltype(entry)>>::value,
+ "The container and predicate type of lessEqualThan should be the same to "
+ "prevent unnecessary conversion.");
+ return !(value < entry);
+ };
+}
+
+template <typename Type>
+auto greaterThan(Type &&value)
+{
+ return [value = std::forward<Type>(value)] (const auto &entry)
+ {
+ static_assert(std::is_same<std::decay_t<Type>,
+ std::decay_t<decltype(entry)>>::value,
+ "The container and predicate type of greaterThan should be the same to "
+ "prevent unnecessary conversion.");
+ return value < entry;
+ };
+}
+
+template <typename Type>
+auto greaterEqualThan(Type &&value)
+{
+ return [value = std::forward<Type>(value)] (const auto &entry)
+ {
+ static_assert(std::is_same<std::decay_t<Type>,
+ std::decay_t<decltype(entry)>>::value,
+ "The container and predicate type of greaterEqualThan should be the same to "
+ "prevent unnecessary conversion.");
+ return !(entry < value);
+ };
+}
+} // namespace Utils
diff --git a/src/shared/lsp/progresssupport.cpp b/src/shared/lsp/progresssupport.cpp
new file mode 100644
index 000000000..6a554b4f4
--- /dev/null
+++ b/src/shared/lsp/progresssupport.cpp
@@ -0,0 +1,54 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "progresssupport.h"
+
+#include <QUuid>
+
+namespace lsp {
+
+ProgressToken::ProgressToken(const QJsonValue &value)
+{
+ if (!QBS_GUARD(value.isDouble() || value.isString()))
+ emplace<QString>(QUuid::createUuid().toString());
+ else if (value.isDouble())
+ emplace<int>(value.toInt());
+ else
+ emplace<QString>(value.toString());
+}
+
+ProgressToken::operator QJsonValue() const
+{
+ if (std::holds_alternative<QString>(*this))
+ return QJsonValue(std::get<QString>(*this));
+ return QJsonValue(std::get<int>(*this));
+}
+
+ProgressParams::ProgressType ProgressParams::value() const
+{
+ QJsonObject paramsValue = JsonObject::value(valueKey).toObject();
+ if (paramsValue[kindKey] == "begin")
+ return ProgressParams::ProgressType(WorkDoneProgressBegin(paramsValue));
+ if (paramsValue[kindKey] == "report")
+ return ProgressParams::ProgressType(WorkDoneProgressReport(paramsValue));
+ return ProgressParams::ProgressType(WorkDoneProgressEnd(paramsValue));
+}
+
+void ProgressParams::setValue(const ProgressParams::ProgressType &value)
+{
+ insertVariant<WorkDoneProgressBegin, WorkDoneProgressReport, WorkDoneProgressEnd>(valueKey, value);
+}
+
+ProgressNotification::ProgressNotification(const ProgressParams &params)
+ : Notification(methodName, params)
+{
+
+}
+
+WorkDoneProgressCreateRequest::WorkDoneProgressCreateRequest(const WorkDoneProgressCreateParams &params)
+ : Request(methodName, params)
+{
+
+}
+
+} // namespace lsp
diff --git a/src/shared/lsp/progresssupport.h b/src/shared/lsp/progresssupport.h
new file mode 100644
index 000000000..8ccc34c37
--- /dev/null
+++ b/src/shared/lsp/progresssupport.h
@@ -0,0 +1,152 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "jsonrpcmessages.h"
+
+#include <QJsonValue>
+
+#include <variant>
+
+namespace lsp {
+
+class LANGUAGESERVERPROTOCOL_EXPORT ProgressToken : public std::variant<int, QString>
+{
+public:
+ using variant::variant;
+ explicit ProgressToken(const QJsonValue &value);
+
+ bool isValid() { return true; }
+ operator QJsonValue() const;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkDoneProgressReport : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ /**
+ * Controls if a cancel button should be shown to allow the user to cancel the
+ * long running operation.
+ * Clients that don't support cancellation can ignore the setting.
+ */
+ std::optional<bool> cancellable() const { return optionalValue<bool>(cancellableKey); }
+ void setCancellable(bool cancellable) { insert(cancellableKey, cancellable); }
+ void clearCancellable() { remove(cancellableKey); }
+
+ /**
+ * Optional, more detailed associated progress message. Contains
+ * complementary information to the `title`.
+ *
+ * Examples: "3/25 files", "project/src/module2", "node_modules/some_dep".
+ * If unset, the previous progress message (if any) is still valid.
+ */
+ std::optional<QString> message() const { return optionalValue<QString>(messageKey); }
+ void setMessage(const QString &message) { insert(messageKey, message); }
+ void clearMessage() { remove(messageKey); }
+
+ /**
+ * Optional progress percentage to display (value 100 is considered 100%).
+ * If not provided infinite progress is assumed and clients are allowed
+ * to ignore the `percentage` value in subsequent in report notifications.
+ *
+ * The value should be steadily rising. Clients are free to ignore values
+ * that are not following this rule.
+ */
+
+ // Allthough percentage is defined as an uint by the protocol some server
+ // return a double here. Be less strict and also use a double.
+ // CAUTION: the range is still 0 - 100 and not 0 - 1
+ std::optional<double> percentage() const { return optionalValue<double>(percentageKey); }
+ void setPercentage(double percentage) { insert(percentageKey, percentage); }
+ void clearPercentage() { remove(percentageKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkDoneProgressBegin : public WorkDoneProgressReport
+{
+public:
+ using WorkDoneProgressReport::WorkDoneProgressReport;
+
+ /**
+ * Mandatory title of the progress operation. Used to briefly inform about
+ * the kind of operation being performed.
+ *
+ * Examples: "Indexing" or "Linking dependencies".
+ */
+
+ QString title() const { return typedValue<QString>(titleKey); }
+ void setTitle(const QString &title) { insert(titleKey, title); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkDoneProgressEnd : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ /**
+ * Optional, a final message indicating to for example indicate the outcome
+ * of the operation.
+ */
+ std::optional<QString> message() const { return optionalValue<QString>(messageKey); }
+ void setMessage(const QString &message) { insert(messageKey, message); }
+ void clearMessage() { remove(messageKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ProgressParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ ProgressToken token() const { return ProgressToken(JsonObject::value(tokenKey)); }
+ void setToken(const ProgressToken &token) { insert(tokenKey, token); }
+
+ using ProgressType
+ = std::variant<WorkDoneProgressBegin, WorkDoneProgressReport, WorkDoneProgressEnd>;
+ ProgressType value() const;
+ void setValue(const ProgressType &value);
+
+ bool isValid() const override { return contains(tokenKey) && contains(valueKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ProgressNotification : public Notification<ProgressParams>
+{
+public:
+ ProgressNotification(const ProgressParams &params);
+ using Notification::Notification;
+ constexpr static const char methodName[] = "$/progress";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ProgressTokenParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ // The token to be used to report progress.
+ ProgressToken token() const { return typedValue<ProgressToken>(tokenKey); }
+ void setToken(const ProgressToken &token) { insert(tokenKey, token); }
+};
+
+using WorkDoneProgressCreateParams = ProgressTokenParams;
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkDoneProgressCreateRequest
+ : public Request<std::nullptr_t, std::nullptr_t, WorkDoneProgressCreateParams>
+{
+public:
+ WorkDoneProgressCreateRequest(const WorkDoneProgressCreateParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "window/workDoneProgress/create";
+};
+
+using WorkDoneProgressCancelParams = ProgressTokenParams;
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkDoneProgressCancelRequest
+ : public Request<std::nullptr_t, std::nullptr_t, WorkDoneProgressCancelParams>
+{
+public:
+ using Request::Request;
+ constexpr static const char methodName[] = "window/workDoneProgress/cancel";
+};
+
+
+} // namespace lsp
diff --git a/src/shared/lsp/semantictokens.cpp b/src/shared/lsp/semantictokens.cpp
new file mode 100644
index 000000000..209966dcf
--- /dev/null
+++ b/src/shared/lsp/semantictokens.cpp
@@ -0,0 +1,141 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "semantictokens.h"
+
+namespace lsp {
+
+bool SemanticTokensLegend::isValid() const
+{
+ return contains(tokenTypesKey) && contains(tokenModifiersKey);
+}
+
+QMap<QString, int> SemanticTokens::defaultTokenTypesMap()
+{
+ QMap<QString, int> map;
+ map.insert("namespace", namespaceToken);
+ map.insert("type", typeToken);
+ map.insert("class", classToken);
+ map.insert("enum", enumToken);
+ map.insert("interface", interfaceToken);
+ map.insert("struct", structToken);
+ map.insert("typeParameter", typeParameterToken);
+ map.insert("parameter", parameterToken);
+ map.insert("variable", variableToken);
+ map.insert("property", propertyToken);
+ map.insert("enumMember", enumMemberToken);
+ map.insert("event", eventToken);
+ map.insert("function", functionToken);
+ map.insert("method", methodToken);
+ map.insert("macro", macroToken);
+ map.insert("keyword", keywordToken);
+ map.insert("modifier", modifierToken);
+ map.insert("comment", commentToken);
+ map.insert("string", stringToken);
+ map.insert("number", numberToken);
+ map.insert("regexp", regexpToken);
+ map.insert("operator", operatorToken);
+ return map;
+}
+
+QMap<QString, int> SemanticTokens::defaultTokenModifiersMap()
+{
+ QMap<QString, int> map;
+ map.insert("declaration", declarationModifier);
+ map.insert("definition", definitionModifier);
+ map.insert("readonly", readonlyModifier);
+ map.insert("static", staticModifier);
+ map.insert("deprecated", deprecatedModifier);
+ map.insert("abstract", abstractModifier);
+ map.insert("async", asyncModifier);
+ map.insert("modification", modificationModifier);
+ map.insert("documentation", documentationModifier);
+ map.insert("defaultLibrary", defaultLibraryModifier);
+ return map;
+}
+
+static int convertModifiers(int modifiersData, const QList<int> &tokenModifiers)
+{
+ int result = 0;
+ for (int i = 0; i < tokenModifiers.size() && modifiersData > 0; ++i) {
+ if (modifiersData & 0x1) {
+ const int modifier = tokenModifiers[i];
+ if (modifier > 0)
+ result |= modifier;
+ }
+ modifiersData = modifiersData >> 1;
+ }
+ return result;
+}
+
+QList<SemanticToken> SemanticTokens::toTokens(const QList<int> &tokenTypes,
+ const QList<int> &tokenModifiers) const
+{
+ const QList<int> &data = this->data();
+ if (data.size() % 5 != 0)
+ return {};
+ QList<SemanticToken> tokens;
+ tokens.reserve(int(data.size() / 5));
+ auto end = data.end();
+ for (auto it = data.begin(); it != end; it += 5) {
+ SemanticToken token;
+ token.deltaLine = *(it);
+ token.deltaStart = *(it + 1);
+ token.length = *(it + 2);
+ token.tokenIndex = *(it + 3);
+ token.tokenType = tokenTypes.value(token.tokenIndex, -1);
+ token.rawTokenModifiers = *(it + 4);
+ token.tokenModifiers = convertModifiers(token.rawTokenModifiers, tokenModifiers);
+ tokens << token;
+ }
+ return tokens;
+}
+
+bool SemanticTokensRangeParams::isValid() const
+{
+ return SemanticTokensParams::isValid() && contains(rangeKey);
+}
+
+SemanticTokensFullRequest::SemanticTokensFullRequest(const SemanticTokensParams &params)
+ : Request(methodName, params)
+{}
+
+SemanticTokensRangeRequest::SemanticTokensRangeRequest(const SemanticTokensRangeParams &params)
+ : Request(methodName, params)
+{}
+
+SemanticTokensResult::SemanticTokensResult(const QJsonValue &value)
+{
+ if (value.isObject())
+ emplace<SemanticTokens>(SemanticTokens(value.toObject()));
+ else
+ emplace<std::nullptr_t>(nullptr);
+}
+
+SemanticTokensFullDeltaRequest::SemanticTokensFullDeltaRequest(const SemanticTokensDeltaParams &params)
+ : Request(methodName, params)
+{}
+
+bool SemanticTokensDeltaParams::isValid() const
+{
+ return SemanticTokensParams::isValid() && contains(previousResultIdKey);
+}
+
+SemanticTokensDeltaResult::SemanticTokensDeltaResult(const QJsonValue &value)
+{
+ if (value.isObject()) {
+ QJsonObject object = value.toObject();
+ if (object.contains(editsKey))
+ emplace<SemanticTokensDelta>(object);
+ else
+ emplace<SemanticTokens>(object);
+ } else {
+ emplace<std::nullptr_t>(nullptr);
+ }
+}
+
+SemanticTokensRefreshRequest::SemanticTokensRefreshRequest()
+ : Request(methodName, nullptr)
+{}
+
+} // namespace lsp
diff --git a/src/shared/lsp/semantictokens.h b/src/shared/lsp/semantictokens.h
new file mode 100644
index 000000000..2dce74aa4
--- /dev/null
+++ b/src/shared/lsp/semantictokens.h
@@ -0,0 +1,230 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "jsonkeys.h"
+#include "jsonobject.h"
+#include "jsonrpcmessages.h"
+#include "languageserverprotocol_global.h"
+#include "lsptypes.h"
+
+namespace lsp {
+
+struct LANGUAGESERVERPROTOCOL_EXPORT SemanticToken
+{
+ int deltaLine = 0;
+ int deltaStart = 0;
+ int length = 0;
+ int tokenIndex = 0;
+ int tokenType = 0;
+ int rawTokenModifiers = 0;
+ int tokenModifiers = 0;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensLegend : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ // The token types a server uses.
+ QList<QString> tokenTypes() const { return array<QString>(tokenTypesKey); }
+ void setTokenTypes(const QList<QString> &tokenTypes) { insertArray(tokenTypesKey, tokenTypes); }
+
+ // The token modifiers a server uses.
+ QList<QString> tokenModifiers() const { return array<QString>(tokenModifiersKey); }
+ void setTokenModifiers(const QList<QString> &value) { insertArray(tokenModifiersKey, value); }
+
+ bool isValid() const override;
+};
+
+enum SemanticTokenTypes {
+ namespaceToken,
+ typeToken,
+ classToken,
+ enumToken,
+ interfaceToken,
+ structToken,
+ typeParameterToken,
+ parameterToken,
+ variableToken,
+ propertyToken,
+ enumMemberToken,
+ eventToken,
+ functionToken,
+ methodToken,
+ macroToken,
+ keywordToken,
+ modifierToken,
+ commentToken,
+ stringToken,
+ numberToken,
+ regexpToken,
+ operatorToken
+};
+
+enum SemanticTokenModifiers {
+ declarationModifier = 0x1,
+ definitionModifier = 0x2,
+ readonlyModifier = 0x4,
+ staticModifier = 0x8,
+ deprecatedModifier = 0x10,
+ abstractModifier = 0x20,
+ asyncModifier = 0x40,
+ modificationModifier = 0x80,
+ documentationModifier = 0x100,
+ defaultLibraryModifier = 0x200
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ TextDocumentIdentifier textDocument() const
+ { return typedValue<TextDocumentIdentifier>(textDocumentKey); }
+ void setTextDocument(const TextDocumentIdentifier &textDocument)
+ { insert(textDocumentKey, textDocument); }
+
+ bool isValid() const override { return contains(textDocumentKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensDeltaParams : public SemanticTokensParams
+{
+public:
+ using SemanticTokensParams::SemanticTokensParams;
+
+ QString previousResultId() const { return typedValue<QString>(previousResultIdKey); }
+ void setPreviousResultId(const QString &previousResultId)
+ {
+ insert(previousResultIdKey, previousResultId);
+ }
+
+ bool isValid() const override;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensRangeParams : public SemanticTokensParams
+{
+public:
+ using SemanticTokensParams::SemanticTokensParams;
+
+ Range range() const { return typedValue<Range>(rangeKey); }
+ void setRange(const Range &range) { insert(rangeKey, range); }
+
+ bool isValid() const override;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokens : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ /**
+ * An optional result id. If provided and clients support delta updating
+ * the client will include the result id in the next semantic token request.
+ * A server can then instead of computing all semantic tokens again simply
+ * send a delta.
+ */
+ std::optional<QString> resultId() const { return optionalValue<QString>(resultIdKey); }
+ void setResultId(const QString &resultId) { insert(resultIdKey, resultId); }
+ void clearResultId() { remove(resultIdKey); }
+
+ /// The actual tokens.
+ QList<int> data() const { return array<int>(dataKey); }
+ void setData(const QList<int> &value) { insertArray(dataKey, value); }
+
+ bool isValid() const override { return contains(dataKey); }
+
+ QList<SemanticToken> toTokens(const QList<int> &tokenTypes,
+ const QList<int> &tokenModifiers) const;
+ static QMap<QString, int> defaultTokenTypesMap();
+ static QMap<QString, int> defaultTokenModifiersMap();
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensResult
+ : public std::variant<SemanticTokens, std::nullptr_t>
+{
+public:
+ using variant::variant;
+ explicit SemanticTokensResult(const QJsonValue &value);
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensFullRequest
+ : public Request<SemanticTokensResult, std::nullptr_t, SemanticTokensParams>
+{
+public:
+ explicit SemanticTokensFullRequest(const SemanticTokensParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/semanticTokens/full";
+};
+
+class SemanticTokensEdit : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ int start() const { return typedValue<int>(startKey); }
+ void setStart(int start) { insert(startKey, start); }
+
+ int deleteCount() const { return typedValue<int>(deleteCountKey); }
+ void setDeleteCount(int deleteCount) { insert(deleteCountKey, deleteCount); }
+
+ std::optional<QList<int>> data() const { return optionalArray<int>(dataKey); }
+ void setData(const QList<int> &value) { insertArray(dataKey, value); }
+ void clearData() { remove(dataKey); }
+
+ int dataSize() const { return contains(dataKey) ? value(dataKey).toArray().size() : 0; }
+
+ bool isValid() const override { return contains(dataKey) && contains(deleteCountKey); }
+};
+
+class SemanticTokensDelta : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ QString resultId() const { return typedValue<QString>(resultIdKey); }
+ void setResultId(const QString &resultId) { insert(resultIdKey, resultId); }
+
+ QList<SemanticTokensEdit> edits() const { return array<SemanticTokensEdit>(editsKey); }
+ void setEdits(const QList<SemanticTokensEdit> &edits) { insertArray(editsKey, edits); }
+
+ bool isValid() const override { return contains(resultIdKey) && contains(editsKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensDeltaResult
+ : public std::variant<SemanticTokens, SemanticTokensDelta, std::nullptr_t>
+{
+public:
+ using variant::variant;
+ explicit SemanticTokensDeltaResult(const QJsonValue &value);
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensFullDeltaRequest
+ : public Request<SemanticTokensDeltaResult, std::nullptr_t, SemanticTokensDeltaParams>
+{
+public:
+ explicit SemanticTokensFullDeltaRequest(const SemanticTokensDeltaParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/semanticTokens/full/delta";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensRangeRequest
+ : public Request<SemanticTokensResult, std::nullptr_t, SemanticTokensRangeParams>
+{
+public:
+ explicit SemanticTokensRangeRequest(const SemanticTokensRangeParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/semanticTokens/range";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensRefreshRequest
+ : public Request<std::nullptr_t, std::nullptr_t, std::nullptr_t>
+{
+public:
+ explicit SemanticTokensRefreshRequest();
+ using Request::Request;
+ constexpr static const char methodName[] = "workspace/semanticTokens/refresh";
+};
+
+} // namespace lsp
diff --git a/src/shared/lsp/servercapabilities.cpp b/src/shared/lsp/servercapabilities.cpp
new file mode 100644
index 000000000..0923f76f3
--- /dev/null
+++ b/src/shared/lsp/servercapabilities.cpp
@@ -0,0 +1,386 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "servercapabilities.h"
+
+namespace lsp {
+
+std::optional<ServerCapabilities::TextDocumentSync> ServerCapabilities::textDocumentSync() const
+{
+ const QJsonValue &sync = value(textDocumentSyncKey);
+ if (sync.isUndefined())
+ return std::nullopt;
+ return std::make_optional(sync.isDouble()
+ ? TextDocumentSync(sync.toInt())
+ : TextDocumentSync(TextDocumentSyncOptions(sync.toObject())));
+}
+
+void ServerCapabilities::setTextDocumentSync(const ServerCapabilities::TextDocumentSync &textDocumentSync)
+{
+ insertVariant<TextDocumentSyncOptions, int>(textDocumentSyncKey, textDocumentSync);
+}
+
+TextDocumentSyncKind ServerCapabilities::textDocumentSyncKindHelper()
+{
+ if (std::optional<TextDocumentSync> sync = textDocumentSync()) {
+ if (auto kind = std::get_if<int>(&*sync))
+ return static_cast<TextDocumentSyncKind>(*kind);
+ if (auto options = std::get_if<TextDocumentSyncOptions>(&*sync)) {
+ if (const std::optional<int> &change = options->change())
+ return static_cast<TextDocumentSyncKind>(*change);
+ }
+ }
+ return TextDocumentSyncKind::None;
+}
+
+std::optional<std::variant<bool, WorkDoneProgressOptions>> ServerCapabilities::hoverProvider()
+ const
+{
+ using RetType = std::variant<bool, WorkDoneProgressOptions>;
+ const QJsonValue &provider = value(hoverProviderKey);
+ if (provider.isBool())
+ return std::make_optional(RetType(provider.toBool()));
+ if (provider.isObject())
+ return std::make_optional(RetType(WorkDoneProgressOptions(provider.toObject())));
+ return std::nullopt;
+}
+
+void ServerCapabilities::setHoverProvider(
+ const std::variant<bool, WorkDoneProgressOptions> &hoverProvider)
+{
+ insertVariant<bool, WorkDoneProgressOptions>(hoverProviderKey, hoverProvider);
+}
+
+std::optional<std::variant<bool, ServerCapabilities::RegistrationOptions>>
+ServerCapabilities::definitionProvider() const
+{
+ using RetType = std::variant<bool, ServerCapabilities::RegistrationOptions>;
+ const QJsonValue &provider = value(definitionProviderKey);
+ if (provider.isUndefined() || !(provider.isBool() || provider.isObject()))
+ return std::nullopt;
+ return std::make_optional(provider.isBool()
+ ? RetType(provider.toBool())
+ : RetType(RegistrationOptions(provider.toObject())));
+}
+
+void ServerCapabilities::setDefinitionProvider(
+ const std::variant<bool, RegistrationOptions> &definitionProvider)
+{
+ insertVariant<bool, RegistrationOptions>(definitionProviderKey, definitionProvider);
+}
+
+std::optional<std::variant<bool, ServerCapabilities::RegistrationOptions>>
+ServerCapabilities::typeDefinitionProvider() const
+{
+ using RetType = std::variant<bool, ServerCapabilities::RegistrationOptions>;
+ const QJsonValue &provider = value(typeDefinitionProviderKey);
+ if (provider.isUndefined() || !(provider.isBool() || provider.isObject()))
+ return std::nullopt;
+ return std::make_optional(provider.isBool()
+ ? RetType(provider.toBool())
+ : RetType(RegistrationOptions(provider.toObject())));
+}
+
+void ServerCapabilities::setTypeDefinitionProvider(
+ const std::variant<bool, ServerCapabilities::RegistrationOptions> &typeDefinitionProvider)
+{
+ insertVariant<bool, ServerCapabilities::RegistrationOptions>(typeDefinitionProviderKey,
+ typeDefinitionProvider);
+}
+
+std::optional<std::variant<bool, ServerCapabilities::RegistrationOptions>>
+ServerCapabilities::implementationProvider() const
+{
+ using RetType = std::variant<bool, ServerCapabilities::RegistrationOptions>;
+ const QJsonValue &provider = value(implementationProviderKey);
+ if (provider.isUndefined() || !(provider.isBool() || provider.isObject()))
+ return std::nullopt;
+ return std::make_optional(provider.isBool()
+ ? RetType(provider.toBool())
+ : RetType(RegistrationOptions(provider.toObject())));
+}
+
+void ServerCapabilities::setImplementationProvider(
+ const std::variant<bool, ServerCapabilities::RegistrationOptions> &implementationProvider)
+{
+ insertVariant<bool, RegistrationOptions>(implementationProviderKey, implementationProvider);
+}
+
+std::optional<std::variant<bool, WorkDoneProgressOptions>>
+ServerCapabilities::referencesProvider() const
+{
+ using RetType = std::variant<bool, WorkDoneProgressOptions>;
+ const QJsonValue &provider = value(referencesProviderKey);
+ if (provider.isBool())
+ return std::make_optional(RetType(provider.toBool()));
+ if (provider.isObject())
+ return std::make_optional(RetType(WorkDoneProgressOptions(provider.toObject())));
+ return std::nullopt;
+}
+
+void ServerCapabilities::setReferencesProvider(
+ const std::variant<bool, WorkDoneProgressOptions> &referencesProvider)
+{
+ insertVariant<bool, WorkDoneProgressOptions>(referencesProviderKey,
+ referencesProvider);
+}
+
+std::optional<std::variant<bool, WorkDoneProgressOptions>>
+ServerCapabilities::documentHighlightProvider() const
+{
+ using RetType = std::variant<bool, WorkDoneProgressOptions>;
+ const QJsonValue &provider = value(documentHighlightProviderKey);
+ if (provider.isBool())
+ return std::make_optional(RetType(provider.toBool()));
+ if (provider.isObject())
+ return std::make_optional(RetType(WorkDoneProgressOptions(provider.toObject())));
+ return std::nullopt;
+}
+
+void ServerCapabilities::setDocumentHighlightProvider(
+ const std::variant<bool, WorkDoneProgressOptions> &documentHighlightProvider)
+{
+ insertVariant<bool, WorkDoneProgressOptions>(documentHighlightProviderKey,
+ documentHighlightProvider);
+}
+
+std::optional<std::variant<bool, WorkDoneProgressOptions>>
+ServerCapabilities::documentSymbolProvider() const
+{
+ using RetType = std::variant<bool, WorkDoneProgressOptions>;
+ const QJsonValue &provider = value(documentSymbolProviderKey);
+ if (provider.isBool())
+ return std::make_optional(RetType(provider.toBool()));
+ if (provider.isObject())
+ return std::make_optional(RetType(WorkDoneProgressOptions(provider.toObject())));
+ return std::nullopt;
+}
+
+void ServerCapabilities::setDocumentSymbolProvider(
+ std::variant<bool, WorkDoneProgressOptions> documentSymbolProvider)
+{
+ insertVariant<bool, WorkDoneProgressOptions>(documentSymbolProviderKey,
+ documentSymbolProvider);
+}
+
+std::optional<SemanticTokensOptions> ServerCapabilities::semanticTokensProvider() const
+{
+ return optionalValue<SemanticTokensOptions>(semanticTokensProviderKey);
+}
+
+void ServerCapabilities::setSemanticTokensProvider(
+ const SemanticTokensOptions &semanticTokensProvider)
+{
+ insert(semanticTokensProviderKey, semanticTokensProvider);
+}
+
+std::optional<std::variant<bool, WorkDoneProgressOptions> >
+ServerCapabilities::callHierarchyProvider() const
+{
+ const QJsonValue &provider = value(callHierarchyProviderKey);
+ if (provider.isBool())
+ return provider.toBool();
+ else if (provider.isObject())
+ return WorkDoneProgressOptions(provider.toObject());
+ return std::nullopt;
+}
+
+void ServerCapabilities::setCallHierarchyProvider(
+ const std::variant<bool, WorkDoneProgressOptions> &callHierarchyProvider)
+{
+ QJsonValue val;
+ if (std::holds_alternative<bool>(callHierarchyProvider))
+ val = std::get<bool>(callHierarchyProvider);
+ else if (std::holds_alternative<WorkDoneProgressOptions>(callHierarchyProvider))
+ val = QJsonObject(std::get<WorkDoneProgressOptions>(callHierarchyProvider));
+ insert(callHierarchyProviderKey, val);
+}
+
+std::optional<std::variant<bool, WorkDoneProgressOptions>>
+ServerCapabilities::workspaceSymbolProvider() const
+{
+ using RetType = std::variant<bool, WorkDoneProgressOptions>;
+ const QJsonValue &provider = value(workspaceSymbolProviderKey);
+ if (provider.isBool())
+ return std::make_optional(RetType(provider.toBool()));
+ if (provider.isObject())
+ return std::make_optional(RetType(WorkDoneProgressOptions(provider.toObject())));
+ return std::nullopt;
+}
+
+void ServerCapabilities::setWorkspaceSymbolProvider(
+ std::variant<bool, WorkDoneProgressOptions> workspaceSymbolProvider)
+{
+ insertVariant<bool, WorkDoneProgressOptions>(workspaceSymbolProviderKey,
+ workspaceSymbolProvider);
+}
+
+std::optional<std::variant<bool, CodeActionOptions>> ServerCapabilities::codeActionProvider() const
+{
+ const QJsonValue &provider = value(codeActionProviderKey);
+ if (provider.isBool())
+ return std::make_optional(std::variant<bool, CodeActionOptions>(provider.toBool()));
+ if (provider.isObject()) {
+ CodeActionOptions options(provider);
+ if (options.isValid())
+ return std::make_optional(std::variant<bool, CodeActionOptions>(options));
+ }
+ return std::nullopt;
+}
+
+std::optional<std::variant<bool, WorkDoneProgressOptions>>
+ServerCapabilities::documentFormattingProvider() const
+{
+ using RetType = std::variant<bool, WorkDoneProgressOptions>;
+ const QJsonValue &provider = value(documentFormattingProviderKey);
+ if (provider.isBool())
+ return std::make_optional(RetType(provider.toBool()));
+ if (provider.isObject())
+ return std::make_optional(RetType(WorkDoneProgressOptions(provider.toObject())));
+ return std::nullopt;
+}
+
+void ServerCapabilities::setDocumentFormattingProvider(
+ const std::variant<bool, WorkDoneProgressOptions> &documentFormattingProvider)
+{
+ insertVariant<bool, WorkDoneProgressOptions>(documentFormattingProviderKey,
+ documentFormattingProvider);
+}
+
+std::optional<std::variant<bool, WorkDoneProgressOptions>>
+ServerCapabilities::documentRangeFormattingProvider() const
+{
+ using RetType = std::variant<bool, WorkDoneProgressOptions>;
+ const QJsonValue &provider = value(documentRangeFormattingProviderKey);
+ if (provider.isBool())
+ return std::make_optional(RetType(provider.toBool()));
+ if (provider.isObject())
+ return std::make_optional(RetType(WorkDoneProgressOptions(provider.toObject())));
+ return std::nullopt;
+}
+
+void ServerCapabilities::setDocumentRangeFormattingProvider(
+ std::variant<bool, WorkDoneProgressOptions> documentRangeFormattingProvider)
+{
+ insertVariant<bool, WorkDoneProgressOptions>(documentRangeFormattingProviderKey,
+ documentRangeFormattingProvider);
+}
+
+std::optional<std::variant<ServerCapabilities::RenameOptions, bool>> ServerCapabilities::renameProvider() const
+{
+ using RetType = std::variant<ServerCapabilities::RenameOptions, bool>;
+ const QJsonValue &localValue = value(renameProviderKey);
+ if (localValue.isBool())
+ return RetType(localValue.toBool());
+ if (localValue.isObject())
+ return RetType(RenameOptions(localValue.toObject()));
+ return std::nullopt;
+}
+
+void ServerCapabilities::setRenameProvider(std::variant<ServerCapabilities::RenameOptions, bool> renameProvider)
+{
+ insertVariant<RenameOptions, bool>(renameProviderKey, renameProvider);
+}
+
+std::optional<std::variant<bool, JsonObject>> ServerCapabilities::colorProvider() const
+{
+ using RetType = std::variant<bool, JsonObject>;
+ const QJsonValue &localValue = value(colorProviderKey);
+ if (localValue.isBool())
+ return RetType(localValue.toBool());
+ if (localValue.isObject())
+ return RetType(JsonObject(localValue.toObject()));
+ return std::nullopt;
+}
+
+void ServerCapabilities::setColorProvider(std::variant<bool, JsonObject> colorProvider)
+{
+ insertVariant<bool, JsonObject>(renameProviderKey, colorProvider);
+}
+
+std::optional<std::variant<QString, bool> >
+ServerCapabilities::WorkspaceServerCapabilities::WorkspaceFoldersCapabilities::changeNotifications() const
+{
+ using RetType = std::variant<QString, bool>;
+ const QJsonValue &change = value(changeNotificationsKey);
+ if (change.isUndefined())
+ return std::nullopt;
+ return std::make_optional(change.isBool() ? RetType(change.toBool())
+ : RetType(change.toString()));
+}
+
+void ServerCapabilities::WorkspaceServerCapabilities::WorkspaceFoldersCapabilities::setChangeNotifications(
+ std::variant<QString, bool> changeNotifications)
+{
+ insertVariant<QString, bool>(changeNotificationsKey, changeNotifications);
+}
+
+bool TextDocumentRegistrationOptions::filterApplies(const Utils::FilePath &fileName) const
+{
+ Q_UNUSED(fileName)
+ return true;
+}
+
+bool ServerCapabilities::ExecuteCommandOptions::isValid() const
+{
+ return WorkDoneProgressOptions::isValid() && contains(commandsKey);
+}
+
+bool CodeActionOptions::isValid() const
+{
+ return WorkDoneProgressOptions::isValid() && contains(codeActionKindsKey);
+}
+
+std::optional<std::variant<bool, QJsonObject>> SemanticTokensOptions::range() const
+{
+ using RetType = std::variant<bool, QJsonObject>;
+ const QJsonValue &rangeOptions = value(rangeKey);
+ if (rangeOptions.isBool())
+ return RetType(rangeOptions.toBool());
+ if (rangeOptions.isObject())
+ return RetType(rangeOptions.toObject());
+ return std::nullopt;
+}
+
+void SemanticTokensOptions::setRange(const std::variant<bool, QJsonObject> &range)
+{
+ insertVariant<bool, QJsonObject>(rangeKey, range);
+}
+
+std::optional<std::variant<bool, SemanticTokensOptions::FullSemanticTokenOptions>>
+SemanticTokensOptions::full() const
+{
+ using RetType = std::variant<bool, SemanticTokensOptions::FullSemanticTokenOptions>;
+ const QJsonValue &fullOptions = value(fullKey);
+ if (fullOptions.isBool())
+ return RetType(fullOptions.toBool());
+ if (fullOptions.isObject())
+ return RetType(FullSemanticTokenOptions(fullOptions.toObject()));
+ return std::nullopt;
+}
+
+void SemanticTokensOptions::setFull(
+ const std::variant<bool, SemanticTokensOptions::FullSemanticTokenOptions> &full)
+{
+ insertVariant<bool, FullSemanticTokenOptions>(fullKey, full);
+}
+
+SemanticRequestTypes SemanticTokensOptions::supportedRequests() const
+{
+ SemanticRequestTypes result;
+ QJsonValue rangeValue = value(rangeKey);
+ if (rangeValue.isObject() || rangeValue.toBool())
+ result |= SemanticRequestType::Range;
+ QJsonValue fullValue = value(fullKey);
+ if (fullValue.isObject()) {
+ SemanticTokensOptions::FullSemanticTokenOptions options(fullValue.toObject());
+ if (options.delta().value_or(false))
+ result |= SemanticRequestType::FullDelta;
+ result |= SemanticRequestType::Full;
+ } else if (fullValue.toBool()) {
+ result |= SemanticRequestType::Full;
+ }
+ return result;
+}
+
+} // namespace lsp
diff --git a/src/shared/lsp/servercapabilities.h b/src/shared/lsp/servercapabilities.h
new file mode 100644
index 000000000..03c0371e8
--- /dev/null
+++ b/src/shared/lsp/servercapabilities.h
@@ -0,0 +1,435 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "lsptypes.h"
+#include "semantictokens.h"
+
+namespace lsp {
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkDoneProgressOptions : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ std::optional<bool> workDoneProgress() const { return optionalValue<bool>(workDoneProgressKey); }
+ void setWorkDoneProgress(bool workDoneProgress) { insert(workDoneProgressKey, workDoneProgress); }
+ void clearWorkDoneProgress() { remove(workDoneProgressKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ResolveProviderOption : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ std::optional<bool> resolveProvider() const { return optionalValue<bool>(resolveProviderKey); }
+ void setResolveProvider(bool resolveProvider) { insert(resolveProviderKey, resolveProvider); }
+ void clearResolveProvider() { remove(resolveProviderKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentRegistrationOptions : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ LanguageClientArray<DocumentFilter> documentSelector() const
+ { return clientArray<DocumentFilter>(documentSelectorKey); }
+ void setDocumentSelector(const LanguageClientArray<DocumentFilter> &documentSelector)
+ { insert(documentSelectorKey, documentSelector.toJson()); }
+
+ bool filterApplies(const Utils::FilePath &fileName) const;
+
+ bool isValid() const override { return contains(documentSelectorKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT SaveOptions : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ // The client is supposed to include the content on save.
+ std::optional<bool> includeText() const { return optionalValue<bool>(includeTextKey); }
+ void setIncludeText(bool includeText) { insert(includeTextKey, includeText); }
+ void clearIncludeText() { remove(includeTextKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentSyncOptions : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ // Open and close notifications are sent to the server.
+ std::optional<bool> openClose() const { return optionalValue<bool>(openCloseKey); }
+ void setOpenClose(bool openClose) { insert(openCloseKey, openClose); }
+ void clearOpenClose() { remove(openCloseKey); }
+
+ // Change notifications are sent to the server. See TextDocumentSyncKind.None,
+ // TextDocumentSyncKind.Full and TextDocumentSyncKind.Incremental.
+ std::optional<int> change() const { return optionalValue<int>(changeKey); }
+ void setChange(int change) { insert(changeKey, change); }
+ void clearChange() { remove(changeKey); }
+
+ // Will save notifications are sent to the server.
+ std::optional<bool> willSave() const { return optionalValue<bool>(willSaveKey); }
+ void setWillSave(bool willSave) { insert(willSaveKey, willSave); }
+ void clearWillSave() { remove(willSaveKey); }
+
+ // Will save wait until requests are sent to the server.
+ std::optional<bool> willSaveWaitUntil() const
+ { return optionalValue<bool>(willSaveWaitUntilKey); }
+ void setWillSaveWaitUntil(bool willSaveWaitUntil)
+ { insert(willSaveWaitUntilKey, willSaveWaitUntil); }
+ void clearWillSaveWaitUntil() { remove(willSaveWaitUntilKey); }
+
+ // Save notifications are sent to the server.
+ std::optional<SaveOptions> save() const { return optionalValue<SaveOptions>(saveKey); }
+ void setSave(const SaveOptions &save) { insert(saveKey, save); }
+ void clearSave() { remove(saveKey); }
+};
+
+enum class TextDocumentSyncKind
+{
+ // Documents should not be synced at all.
+ None = 0,
+ // Documents are synced by always sending the full content of the document.
+ Full = 1,
+ // Documents are synced by sending the full content on open.
+ // After that only incremental updates to the document are send.
+ Incremental = 2
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT CodeActionOptions : public WorkDoneProgressOptions
+{
+public:
+ using WorkDoneProgressOptions::WorkDoneProgressOptions;
+
+ QList<QString> codeActionKinds() const { return array<QString>(codeActionKindsKey); }
+ void setCodeActionKinds(const QList<QString> &codeActionKinds)
+ { insertArray(codeActionKindsKey, codeActionKinds); }
+
+ bool isValid() const override;
+};
+
+enum class SemanticRequestType {
+ None = 0x0,
+ Full = 0x1,
+ FullDelta = 0x2,
+ Range = 0x4
+};
+Q_DECLARE_FLAGS(SemanticRequestTypes, SemanticRequestType)
+
+class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensOptions : public WorkDoneProgressOptions
+{
+public:
+ using WorkDoneProgressOptions::WorkDoneProgressOptions;
+
+ /// The legend used by the server
+ SemanticTokensLegend legend() const { return typedValue<SemanticTokensLegend>(legendKey); }
+ void setLegend(const SemanticTokensLegend &legend) { insert(legendKey, legend); }
+
+ /// Server supports providing semantic tokens for a specific range of a document.
+ std::optional<std::variant<bool, QJsonObject>> range() const;
+ void setRange(const std::variant<bool, QJsonObject> &range);
+ void clearRange() { remove(rangeKey); }
+
+ class FullSemanticTokenOptions : public JsonObject
+ {
+ public:
+ using JsonObject::JsonObject;
+
+ /// The server supports deltas for full documents.
+ std::optional<bool> delta() const { return optionalValue<bool>(deltaKey); }
+ void setDelta(bool delta) { insert(deltaKey, delta); }
+ void clearDelta() { remove(deltaKey); }
+ };
+
+ /// Server supports providing semantic tokens for a full document.
+ std::optional<std::variant<bool, FullSemanticTokenOptions>> full() const;
+ void setFull(const std::variant<bool, FullSemanticTokenOptions> &full);
+ void clearFull() { remove(fullKey); }
+
+ bool isValid() const override { return contains(legendKey); }
+
+ SemanticRequestTypes supportedRequests() const;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ServerCapabilities : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ // Defines how the host (editor) should sync document changes to the language server.
+
+ class LANGUAGESERVERPROTOCOL_EXPORT CompletionOptions : public WorkDoneProgressOptions
+ {
+ public:
+ using WorkDoneProgressOptions::WorkDoneProgressOptions;
+
+ // The characters that trigger completion automatically.
+ std::optional<QList<QString>> triggerCharacters() const
+ { return optionalArray<QString>(triggerCharactersKey); }
+ void setTriggerCharacters(const QList<QString> &triggerCharacters)
+ { insertArray(triggerCharactersKey, triggerCharacters); }
+ void clearTriggerCharacters() { remove(triggerCharactersKey); }
+
+ std::optional<bool> resolveProvider() const { return optionalValue<bool>(resolveProviderKey); }
+ void setResolveProvider(bool resolveProvider) { insert(resolveProviderKey, resolveProvider); }
+ void clearResolveProvider() { remove(resolveProviderKey); }
+ };
+
+ class LANGUAGESERVERPROTOCOL_EXPORT SignatureHelpOptions : public WorkDoneProgressOptions
+ {
+ public:
+ using WorkDoneProgressOptions::WorkDoneProgressOptions;
+
+ // The characters that trigger signature help automatically.
+ std::optional<QList<QString>> triggerCharacters() const
+ { return optionalArray<QString>(triggerCharactersKey); }
+ void setTriggerCharacters(const QList<QString> &triggerCharacters)
+ { insertArray(triggerCharactersKey, triggerCharacters); }
+ void clearTriggerCharacters() { remove(triggerCharactersKey); }
+ };
+
+ using CodeLensOptions = ResolveProviderOption;
+
+ class LANGUAGESERVERPROTOCOL_EXPORT DocumentOnTypeFormattingOptions : public JsonObject
+ {
+ public:
+ using JsonObject::JsonObject;
+
+ // A character on which formatting should be triggered, like `}`.
+ QString firstTriggerCharacter() const { return typedValue<QString>(firstTriggerCharacterKey); }
+ void setFirstTriggerCharacter(QString firstTriggerCharacter)
+ { insert(firstTriggerCharacterKey, firstTriggerCharacter); }
+
+ // More trigger characters.
+ std::optional<QList<QString>> moreTriggerCharacter() const
+ { return optionalArray<QString>(moreTriggerCharacterKey); }
+ void setMoreTriggerCharacter(const QList<QString> &moreTriggerCharacter)
+ { insertArray(moreTriggerCharacterKey, moreTriggerCharacter); }
+ void clearMoreTriggerCharacter() { remove(moreTriggerCharacterKey); }
+
+ bool isValid() const override { return contains(firstTriggerCharacterKey); }
+ };
+
+ using DocumentLinkOptions = ResolveProviderOption;
+
+ class LANGUAGESERVERPROTOCOL_EXPORT ExecuteCommandOptions : public WorkDoneProgressOptions
+ {
+ public:
+ using WorkDoneProgressOptions::WorkDoneProgressOptions;
+
+ QList<QString> commands() const { return array<QString>(commandsKey); }
+ void setCommands(const QList<QString> &commands) { insertArray(commandsKey, commands); }
+
+ bool isValid() const override;
+ };
+
+ using ColorProviderOptions = JsonObject;
+
+ class LANGUAGESERVERPROTOCOL_EXPORT StaticRegistrationOptions : public JsonObject
+ {
+ public:
+ using JsonObject::JsonObject;
+
+ // The id used to register the request. The id can be used to deregister
+ // the request again. See also Registration#id.
+ std::optional<QString> id() const { return optionalValue<QString>(idKey); }
+ void setId(const QString &id) { insert(idKey, id); }
+ void clearId() { remove(idKey); }
+ };
+
+ // Defines how text documents are synced. Is either a detailed structure defining each
+ // notification or for backwards compatibility the TextDocumentSyncKind number.
+ using TextDocumentSync = std::variant<TextDocumentSyncOptions, int>;
+ std::optional<TextDocumentSync> textDocumentSync() const;
+ void setTextDocumentSync(const TextDocumentSync &textDocumentSync);
+ void clearTextDocumentSync() { remove(textDocumentSyncKey); }
+
+ TextDocumentSyncKind textDocumentSyncKindHelper();
+
+ // The server provides hover support.
+ std::optional<std::variant<bool, WorkDoneProgressOptions>> hoverProvider() const;
+ void setHoverProvider(const std::variant<bool, WorkDoneProgressOptions> &hoverProvider);
+ void clearHoverProvider() { remove(hoverProviderKey); }
+
+ // The server provides completion support.
+ std::optional<CompletionOptions> completionProvider() const
+ { return optionalValue<CompletionOptions>(completionProviderKey); }
+ void setCompletionProvider(const CompletionOptions &completionProvider)
+ { insert(completionProviderKey, completionProvider); }
+ void clearCompletionProvider() { remove(completionProviderKey); }
+
+ // The server provides signature help support.
+ std::optional<SignatureHelpOptions> signatureHelpProvider() const
+ { return optionalValue<SignatureHelpOptions>(signatureHelpProviderKey); }
+ void setSignatureHelpProvider(const SignatureHelpOptions &signatureHelpProvider)
+ { insert(signatureHelpProviderKey, signatureHelpProvider); }
+ void clearSignatureHelpProvider() { remove(signatureHelpProviderKey); }
+
+ class LANGUAGESERVERPROTOCOL_EXPORT RegistrationOptions : public JsonObject
+ {
+ public:
+ using JsonObject::JsonObject;
+
+ LanguageClientArray<DocumentFilter> documentSelector() const
+ { return clientArray<DocumentFilter>(documentSelectorKey); }
+ void setDocumentSelector(const LanguageClientArray<DocumentFilter> &documentSelector)
+ { insert(documentSelectorKey, documentSelector.toJson()); }
+
+ bool filterApplies(const Utils::FilePath &fileName) const;
+
+ // The id used to register the request. The id can be used to deregister
+ // the request again. See also Registration#id.
+ std::optional<QString> id() const { return optionalValue<QString>(idKey); }
+ void setId(const QString &id) { insert(idKey, id); }
+ void clearId() { remove(idKey); }
+
+ bool isValid() const override { return contains(documentSelectorKey); }
+ };
+
+ // The server provides goto definition support.
+ std::optional<std::variant<bool, RegistrationOptions>> definitionProvider() const;
+ void setDefinitionProvider(const std::variant<bool, RegistrationOptions> &typeDefinitionProvider);
+ void clearDefinitionProvider() { remove(typeDefinitionProviderKey); }
+
+ // The server provides Goto Type Definition support.
+ std::optional<std::variant<bool, RegistrationOptions>> typeDefinitionProvider() const;
+ void setTypeDefinitionProvider(const std::variant<bool, RegistrationOptions> &typeDefinitionProvider);
+ void clearTypeDefinitionProvider() { remove(typeDefinitionProviderKey); }
+
+ // The server provides Goto Implementation support.
+ std::optional<std::variant<bool, RegistrationOptions>> implementationProvider() const;
+ void setImplementationProvider(const std::variant<bool, RegistrationOptions> &implementationProvider);
+ void clearImplementationProvider() { remove(implementationProviderKey); }
+
+ // The server provides find references support.
+ std::optional<std::variant<bool, WorkDoneProgressOptions>> referencesProvider() const;
+ void setReferencesProvider(const std::variant<bool, WorkDoneProgressOptions> &referencesProvider);
+ void clearReferencesProvider() { remove(referencesProviderKey); }
+
+ // The server provides document highlight support.
+ std::optional<std::variant<bool, WorkDoneProgressOptions>> documentHighlightProvider() const;
+ void setDocumentHighlightProvider(
+ const std::variant<bool, WorkDoneProgressOptions> &documentHighlightProvider);
+ void clearDocumentHighlightProvider() { remove(documentHighlightProviderKey); }
+
+ // The server provides document symbol support.
+ std::optional<std::variant<bool, WorkDoneProgressOptions>> documentSymbolProvider() const;
+ void setDocumentSymbolProvider(std::variant<bool, WorkDoneProgressOptions> documentSymbolProvider);
+ void clearDocumentSymbolProvider() { remove(documentSymbolProviderKey); }
+
+ std::optional<SemanticTokensOptions> semanticTokensProvider() const;
+ void setSemanticTokensProvider(const SemanticTokensOptions &semanticTokensProvider);
+ void clearSemanticTokensProvider() { remove(semanticTokensProviderKey); }
+
+ std::optional<std::variant<bool, WorkDoneProgressOptions>> callHierarchyProvider() const;
+ void setCallHierarchyProvider(const std::variant<bool, WorkDoneProgressOptions> &callHierarchyProvider);
+ void clearCallHierarchyProvider() { remove(callHierarchyProviderKey); }
+
+ // The server provides workspace symbol support.
+ std::optional<std::variant<bool, WorkDoneProgressOptions>> workspaceSymbolProvider() const;
+ void setWorkspaceSymbolProvider(std::variant<bool, WorkDoneProgressOptions> workspaceSymbolProvider);
+ void clearWorkspaceSymbolProvider() { remove(workspaceSymbolProviderKey); }
+
+ // The server provides code actions.
+ std::optional<std::variant<bool, CodeActionOptions>> codeActionProvider() const;
+ void setCodeActionProvider(bool codeActionProvider)
+ { insert(codeActionProviderKey, codeActionProvider); }
+ void setCodeActionProvider(CodeActionOptions options)
+ { insert(codeActionProviderKey, options); }
+ void clearCodeActionProvider() { remove(codeActionProviderKey); }
+
+ // The server provides code lens.
+ std::optional<CodeLensOptions> codeLensProvider() const
+ { return optionalValue<CodeLensOptions>(codeLensProviderKey); }
+ void setCodeLensProvider(CodeLensOptions codeLensProvider)
+ { insert(codeLensProviderKey, codeLensProvider); }
+ void clearCodeLensProvider() { remove(codeLensProviderKey); }
+
+ // The server provides document formatting.
+ std::optional<std::variant<bool, WorkDoneProgressOptions>> documentFormattingProvider() const;
+ void setDocumentFormattingProvider(
+ const std::variant<bool, WorkDoneProgressOptions> &documentFormattingProvider);
+ void clearDocumentFormattingProvider() { remove(documentFormattingProviderKey); }
+
+ // The server provides document formatting on typing.
+ std::optional<std::variant<bool, WorkDoneProgressOptions>> documentRangeFormattingProvider() const;
+ void setDocumentRangeFormattingProvider(std::variant<bool, WorkDoneProgressOptions> documentRangeFormattingProvider);
+ void clearDocumentRangeFormattingProvider() { remove(documentRangeFormattingProviderKey); }
+
+ class LANGUAGESERVERPROTOCOL_EXPORT RenameOptions : public WorkDoneProgressOptions
+ {
+ public:
+ using WorkDoneProgressOptions::WorkDoneProgressOptions;
+
+ // Renames should be checked and tested before being executed.
+ std::optional<bool> prepareProvider() const { return optionalValue<bool>(prepareProviderKey); }
+ void setPrepareProvider(bool prepareProvider) { insert(prepareProviderKey, prepareProvider); }
+ void clearPrepareProvider() { remove(prepareProviderKey); }
+ };
+
+ // The server provides rename support.
+ std::optional<std::variant<RenameOptions, bool>> renameProvider() const;
+ void setRenameProvider(std::variant<RenameOptions,bool> renameProvider);
+ void clearRenameProvider() { remove(renameProviderKey); }
+
+ // The server provides document link support.
+ std::optional<DocumentLinkOptions> documentLinkProvider() const
+ { return optionalValue<DocumentLinkOptions>(documentLinkProviderKey); }
+ void setDocumentLinkProvider(const DocumentLinkOptions &documentLinkProvider)
+ { insert(documentLinkProviderKey, documentLinkProvider); }
+ void clearDocumentLinkProvider() { remove(documentLinkProviderKey); }
+
+ // The server provides color provider support.
+ std::optional<std::variant<bool, JsonObject>> colorProvider() const;
+ void setColorProvider(std::variant<bool, JsonObject> colorProvider);
+ void clearColorProvider() { remove(colorProviderKey); }
+
+ // The server provides execute command support.
+ std::optional<ExecuteCommandOptions> executeCommandProvider() const
+ { return optionalValue<ExecuteCommandOptions>(executeCommandProviderKey); }
+ void setExecuteCommandProvider(ExecuteCommandOptions executeCommandProvider)
+ { insert(executeCommandProviderKey, executeCommandProvider); }
+ void clearExecuteCommandProvider() { remove(executeCommandProviderKey); }
+
+ class LANGUAGESERVERPROTOCOL_EXPORT WorkspaceServerCapabilities : public JsonObject
+ {
+ public:
+ using JsonObject::JsonObject;
+
+ class LANGUAGESERVERPROTOCOL_EXPORT WorkspaceFoldersCapabilities : public JsonObject
+ {
+ public:
+ using JsonObject::JsonObject;
+
+ // The server has support for workspace folders
+ std::optional<bool> supported() const { return optionalValue<bool>(supportedKey); }
+ void setSupported(bool supported) { insert(supportedKey, supported); }
+ void clearSupported() { remove(supportedKey); }
+
+ std::optional<std::variant<QString, bool>> changeNotifications() const;
+ void setChangeNotifications(std::variant<QString, bool> changeNotifications);
+ void clearChangeNotifications() { remove(changeNotificationsKey); }
+ };
+
+ std::optional<WorkspaceFoldersCapabilities> workspaceFolders() const
+ { return optionalValue<WorkspaceFoldersCapabilities>(workspaceFoldersKey); }
+ void setWorkspaceFolders(const WorkspaceFoldersCapabilities &workspaceFolders)
+ { insert(workspaceFoldersKey, workspaceFolders); }
+ void clearWorkspaceFolders() { remove(workspaceFoldersKey); }
+ };
+
+ std::optional<WorkspaceServerCapabilities> workspace() const
+ { return optionalValue<WorkspaceServerCapabilities>(workspaceKey); }
+ void setWorkspace(const WorkspaceServerCapabilities &workspace)
+ { insert(workspaceKey, workspace); }
+ void clearWorkspace() { remove(workspaceKey); }
+
+ std::optional<JsonObject> experimental() const { return optionalValue<JsonObject>(experimentalKey); }
+ void setExperimental(const JsonObject &experimental) { insert(experimentalKey, experimental); }
+ void clearExperimental() { remove(experimentalKey); }
+};
+
+} // namespace LanguageClient
diff --git a/src/shared/lsp/shutdownmessages.cpp b/src/shared/lsp/shutdownmessages.cpp
new file mode 100644
index 000000000..21c41c1d3
--- /dev/null
+++ b/src/shared/lsp/shutdownmessages.cpp
@@ -0,0 +1,13 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "shutdownmessages.h"
+
+namespace lsp {
+
+constexpr const char ShutdownRequest::methodName[];
+constexpr const char ExitNotification::methodName[];
+ShutdownRequest::ShutdownRequest() : Request(methodName, nullptr) { }
+ExitNotification::ExitNotification() : Notification(methodName) { }
+
+} // namespace lsp
diff --git a/src/shared/lsp/shutdownmessages.h b/src/shared/lsp/shutdownmessages.h
new file mode 100644
index 000000000..2e8da4c66
--- /dev/null
+++ b/src/shared/lsp/shutdownmessages.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "jsonrpcmessages.h"
+
+namespace lsp {
+
+class LANGUAGESERVERPROTOCOL_EXPORT ShutdownRequest : public Request<
+ std::nullptr_t, std::nullptr_t, std::nullptr_t>
+{
+public:
+ ShutdownRequest();
+ using Request::Request;
+ constexpr static const char methodName[] = "shutdown";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ExitNotification : public Notification<std::nullptr_t>
+{
+public:
+ ExitNotification();
+ using Notification::Notification;
+ constexpr static const char methodName[] = "exit";
+
+ bool parametersAreValid(QString * /*errorMessage*/) const final { return true; }
+};
+
+} // namespace LanguageClient
diff --git a/src/shared/lsp/textsynchronization.cpp b/src/shared/lsp/textsynchronization.cpp
new file mode 100644
index 000000000..ba9ee2f32
--- /dev/null
+++ b/src/shared/lsp/textsynchronization.cpp
@@ -0,0 +1,84 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "textsynchronization.h"
+
+namespace lsp {
+
+constexpr const char DidOpenTextDocumentNotification::methodName[];
+constexpr const char DidChangeTextDocumentNotification::methodName[];
+constexpr const char WillSaveTextDocumentNotification::methodName[];
+constexpr const char WillSaveWaitUntilTextDocumentRequest::methodName[];
+constexpr const char DidSaveTextDocumentNotification::methodName[];
+constexpr const char DidCloseTextDocumentNotification::methodName[];
+
+DidOpenTextDocumentNotification::DidOpenTextDocumentNotification(
+ const DidOpenTextDocumentParams &params)
+ : Notification(methodName, params)
+{ }
+
+DidChangeTextDocumentNotification::DidChangeTextDocumentNotification(
+ const DidChangeTextDocumentParams &params)
+ : DidChangeTextDocumentNotification(methodName, params)
+{ }
+
+WillSaveTextDocumentNotification::WillSaveTextDocumentNotification(
+ const WillSaveTextDocumentParams &params)
+ : Notification(methodName, params)
+{ }
+
+WillSaveWaitUntilTextDocumentRequest::WillSaveWaitUntilTextDocumentRequest(const WillSaveTextDocumentParams &params)
+ : Request(methodName, params)
+{ }
+
+DidSaveTextDocumentNotification::DidSaveTextDocumentNotification(
+ const DidSaveTextDocumentParams &params)
+ : Notification(methodName, params)
+{ }
+
+DidCloseTextDocumentNotification::DidCloseTextDocumentNotification(
+ const DidCloseTextDocumentParams &params)
+ : Notification(methodName, params)
+{ }
+
+DidChangeTextDocumentParams::DidChangeTextDocumentParams()
+ : DidChangeTextDocumentParams(VersionedTextDocumentIdentifier())
+{ }
+
+DidChangeTextDocumentParams::DidChangeTextDocumentParams(
+ const VersionedTextDocumentIdentifier &docId, const QString &text)
+{
+ setTextDocument(docId);
+ setContentChanges({TextDocumentContentChangeEvent(text)});
+}
+
+DidOpenTextDocumentParams::DidOpenTextDocumentParams(const TextDocumentItem &document)
+{
+ setTextDocument(document);
+}
+
+DidCloseTextDocumentParams::DidCloseTextDocumentParams(const TextDocumentIdentifier &document)
+{
+ setTextDocument(document);
+}
+
+DidChangeTextDocumentParams::TextDocumentContentChangeEvent::TextDocumentContentChangeEvent(
+ const QString &text)
+{
+ setText(text);
+}
+
+DidSaveTextDocumentParams::DidSaveTextDocumentParams(const TextDocumentIdentifier &document)
+{
+ setTextDocument(document);
+}
+
+WillSaveTextDocumentParams::WillSaveTextDocumentParams(
+ const TextDocumentIdentifier &document,
+ const WillSaveTextDocumentParams::TextDocumentSaveReason &reason)
+{
+ setTextDocument(document);
+ setReason(reason);
+}
+
+} // namespace lsp
diff --git a/src/shared/lsp/textsynchronization.h b/src/shared/lsp/textsynchronization.h
new file mode 100644
index 000000000..9ec3d4164
--- /dev/null
+++ b/src/shared/lsp/textsynchronization.h
@@ -0,0 +1,215 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "jsonrpcmessages.h"
+#include "servercapabilities.h"
+
+namespace lsp {
+
+class LANGUAGESERVERPROTOCOL_EXPORT DidOpenTextDocumentParams : public JsonObject
+{
+public:
+ DidOpenTextDocumentParams() = default;
+ explicit DidOpenTextDocumentParams(const TextDocumentItem &document);
+ using JsonObject::JsonObject;
+
+ TextDocumentItem textDocument() const { return typedValue<TextDocumentItem>(textDocumentKey); }
+ void setTextDocument(TextDocumentItem textDocument) { insert(textDocumentKey, textDocument); }
+
+ bool isValid() const override { return contains(textDocumentKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DidOpenTextDocumentNotification : public Notification<
+ DidOpenTextDocumentParams>
+{
+public:
+ explicit DidOpenTextDocumentNotification(const DidOpenTextDocumentParams &params);
+ using Notification::Notification;
+ constexpr static const char methodName[] = "textDocument/didOpen";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentChangeRegistrationOptions : public JsonObject
+{
+public:
+ TextDocumentChangeRegistrationOptions();
+ explicit TextDocumentChangeRegistrationOptions(TextDocumentSyncKind kind);
+ using JsonObject::JsonObject;
+
+ TextDocumentSyncKind syncKind() const
+ { return static_cast<TextDocumentSyncKind>(typedValue<int>(syncKindKey)); }
+ void setSyncKind(TextDocumentSyncKind syncKind)
+ { insert(syncKindKey, static_cast<int>(syncKind)); }
+
+ bool isValid() const override { return contains(syncKindKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DidChangeTextDocumentParams : public JsonObject
+{
+public:
+ DidChangeTextDocumentParams();
+ explicit DidChangeTextDocumentParams(const VersionedTextDocumentIdentifier &docId,
+ const QString &text = QString());
+ using JsonObject::JsonObject;
+
+ VersionedTextDocumentIdentifier textDocument() const
+ { return typedValue<VersionedTextDocumentIdentifier>(textDocumentKey); }
+ void setTextDocument(const VersionedTextDocumentIdentifier &textDocument)
+ { insert(textDocumentKey, textDocument); }
+
+ class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentContentChangeEvent : public JsonObject
+ {
+ /*
+ * An event describing a change to a text document. If range and rangeLength are omitted
+ * the new text is considered to be the full content of the document.
+ */
+ public:
+ TextDocumentContentChangeEvent() = default;
+ explicit TextDocumentContentChangeEvent(const QString &text);
+ using JsonObject::JsonObject;
+
+ // The range of the document that changed.
+ std::optional<Range> range() const { return optionalValue<Range>(rangeKey); }
+ void setRange(Range range) { insert(rangeKey, range); }
+ void clearRange() { remove(rangeKey); }
+
+ // The length of the range that got replaced.
+ std::optional<int> rangeLength() const { return optionalValue<int>(rangeLengthKey); }
+ void setRangeLength(int rangeLength) { insert(rangeLengthKey, rangeLength); }
+ void clearRangeLength() { remove(rangeLengthKey); }
+
+ // The new text of the range/document.
+ QString text() const { return typedValue<QString>(textKey); }
+ void setText(const QString &text) { insert(textKey, text); }
+
+ bool isValid() const override { return contains(textKey); }
+ };
+
+ QList<TextDocumentContentChangeEvent> contentChanges() const
+ { return array<TextDocumentContentChangeEvent>(contentChangesKey); }
+ void setContentChanges(const QList<TextDocumentContentChangeEvent> &contentChanges)
+ { insertArray(contentChangesKey, contentChanges); }
+
+ bool isValid() const override
+ { return contains(textDocumentKey) && contains(contentChangesKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DidChangeTextDocumentNotification : public Notification<
+ DidChangeTextDocumentParams>
+{
+public:
+ explicit DidChangeTextDocumentNotification(const DidChangeTextDocumentParams &params);
+ using Notification::Notification;
+ constexpr static const char methodName[] = "textDocument/didChange";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT WillSaveTextDocumentParams : public JsonObject
+{
+public:
+ enum class TextDocumentSaveReason {
+ Manual = 1,
+ AfterDelay = 2,
+ FocusOut = 3
+ };
+
+ WillSaveTextDocumentParams() : WillSaveTextDocumentParams(TextDocumentIdentifier()) {}
+ explicit WillSaveTextDocumentParams(
+ const TextDocumentIdentifier &document,
+ const TextDocumentSaveReason &reason = TextDocumentSaveReason::Manual);
+ using JsonObject::JsonObject;
+
+ TextDocumentIdentifier textDocument() const
+ { return typedValue<TextDocumentIdentifier>(textDocumentKey); }
+ void setTextDocument(const TextDocumentIdentifier &textDocument)
+ { insert(textDocumentKey, textDocument); }
+
+ TextDocumentSaveReason reason() const
+ { return static_cast<TextDocumentSaveReason>(typedValue<int>(reasonKey)); }
+ void setReason(TextDocumentSaveReason reason) { insert(reasonKey, static_cast<int>(reason)); }
+
+ bool isValid() const override { return contains(textDocumentKey) && contains(reasonKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT WillSaveTextDocumentNotification : public Notification<
+ WillSaveTextDocumentParams>
+{
+public:
+ explicit WillSaveTextDocumentNotification(const WillSaveTextDocumentParams &params);
+ using Notification::Notification;
+ constexpr static const char methodName[] = "textDocument/willSave";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT WillSaveWaitUntilTextDocumentRequest : public Request<
+ LanguageClientArray<TextEdit>, std::nullptr_t, WillSaveTextDocumentParams>
+{
+public:
+ explicit WillSaveWaitUntilTextDocumentRequest(const WillSaveTextDocumentParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "textDocument/willSaveWaitUntil";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentSaveRegistrationOptions
+ : public TextDocumentRegistrationOptions
+{
+public:
+ using TextDocumentRegistrationOptions::TextDocumentRegistrationOptions;
+
+ std::optional<bool> includeText() const { return optionalValue<bool>(includeTextKey); }
+ void setIncludeText(bool includeText) { insert(includeTextKey, includeText); }
+ void clearIncludeText() { remove(includeTextKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DidSaveTextDocumentParams : public JsonObject
+{
+public:
+ DidSaveTextDocumentParams() : DidSaveTextDocumentParams(TextDocumentIdentifier()) {}
+ explicit DidSaveTextDocumentParams(const TextDocumentIdentifier &document);
+ using JsonObject::JsonObject;
+
+ TextDocumentIdentifier textDocument()
+ const { return typedValue<TextDocumentIdentifier>(textDocumentKey); }
+ void setTextDocument(TextDocumentIdentifier textDocument)
+ { insert(textDocumentKey, textDocument); }
+
+ std::optional<QString> text() const { return optionalValue<QString>(textKey); }
+ void setText(const QString &text) { insert(textKey, text); }
+ void clearText() { remove(textKey); }
+
+ bool isValid() const override { return contains(textDocumentKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DidSaveTextDocumentNotification : public Notification<
+ DidSaveTextDocumentParams>
+{
+public:
+ explicit DidSaveTextDocumentNotification(const DidSaveTextDocumentParams &params);
+ using Notification::Notification;
+ constexpr static const char methodName[] = "textDocument/didSave";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DidCloseTextDocumentParams : public JsonObject
+{
+public:
+ DidCloseTextDocumentParams() = default;
+ explicit DidCloseTextDocumentParams(const TextDocumentIdentifier &document);
+ using JsonObject::JsonObject;
+
+ TextDocumentIdentifier textDocument() const
+ { return typedValue<TextDocumentIdentifier>(textDocumentKey); }
+ void setTextDocument(const TextDocumentIdentifier &textDocument)
+ { insert(textDocumentKey, textDocument); }
+
+ bool isValid() const override { return contains(textDocumentKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DidCloseTextDocumentNotification : public Notification<
+ DidCloseTextDocumentParams>
+{
+public:
+ explicit DidCloseTextDocumentNotification(const DidCloseTextDocumentParams &params);
+ using Notification::Notification;
+ constexpr static const char methodName[] = "textDocument/didClose";
+};
+
+} // namespace LanguageClient
diff --git a/src/shared/lsp/textutils.cpp b/src/shared/lsp/textutils.cpp
new file mode 100644
index 000000000..1c0bff9d0
--- /dev/null
+++ b/src/shared/lsp/textutils.cpp
@@ -0,0 +1,126 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "textutils.h"
+
+#include <tools/qbsassert.h>
+
+#include <QRegularExpression>
+#include <QtDebug>
+
+namespace lsp::Utils::Text {
+
+bool Position::operator==(const Position &other) const
+{
+ return line == other.line && column == other.column;
+}
+
+/*!
+ Returns the text position of a \a fileName and sets the \a postfixPos if
+ it can find a positional postfix.
+
+ The following patterns are supported: \c {filepath.txt:19},
+ \c{filepath.txt:19:12}, \c {filepath.txt+19},
+ \c {filepath.txt+19+12}, and \c {filepath.txt(19)}.
+*/
+
+Position Position::fromFileName(QStringView fileName, int &postfixPos)
+{
+ static const auto regexp = QRegularExpression("[:+](\\d+)?([:+](\\d+)?)?$");
+ // (10) MSVC-style
+ static const auto vsRegexp = QRegularExpression("[(]((\\d+)[)]?)?$");
+ const QRegularExpressionMatch match = regexp.match(fileName);
+ Position pos;
+ if (match.hasMatch()) {
+ postfixPos = match.capturedStart(0);
+ if (match.lastCapturedIndex() > 0) {
+ pos.line = match.captured(1).toInt();
+ if (match.lastCapturedIndex() > 2) // index 2 includes the + or : for the column number
+ pos.column = match.captured(3).toInt() - 1; //column is 0 based, despite line being 1 based
+ }
+ } else {
+ const QRegularExpressionMatch vsMatch = vsRegexp.match(fileName);
+ postfixPos = vsMatch.capturedStart(0);
+ if (vsMatch.lastCapturedIndex() > 1) // index 1 includes closing )
+ pos.line = vsMatch.captured(2).toInt();
+ }
+ if (pos.line > 0 && pos.column < 0)
+ pos.column = 0; // if we got a valid line make sure to return a valid TextPosition
+ return pos;
+}
+
+int Range::length(const QString &text) const
+{
+ if (end.line < begin.line)
+ return -1;
+
+ if (begin.line == end.line)
+ return end.column - begin.column;
+
+ int index = 0;
+ int currentLine = 1;
+ while (currentLine < begin.line) {
+ index = text.indexOf(QChar::LineFeed, index);
+ if (index < 0)
+ return -1;
+ ++index;
+ ++currentLine;
+ }
+ const int beginIndex = index + begin.column;
+ while (currentLine < end.line) {
+ index = text.indexOf(QChar::LineFeed, index);
+ if (index < 0)
+ return -1;
+ ++index;
+ ++currentLine;
+ }
+ return index + end.column - beginIndex;
+}
+
+bool Range::operator==(const Range &other) const
+{
+ return begin == other.begin && end == other.end;
+}
+
+QString utf16LineTextInUtf8Buffer(const QByteArray &utf8Buffer, int currentUtf8Offset)
+{
+ const int lineStartUtf8Offset = currentUtf8Offset
+ ? (utf8Buffer.lastIndexOf('\n', currentUtf8Offset - 1) + 1)
+ : 0;
+ const int lineEndUtf8Offset = utf8Buffer.indexOf('\n', currentUtf8Offset);
+ return QString::fromUtf8(
+ utf8Buffer.mid(lineStartUtf8Offset, lineEndUtf8Offset - lineStartUtf8Offset));
+}
+
+static bool isByteOfMultiByteCodePoint(unsigned char byte)
+{
+ return byte & 0x80; // Check if most significant bit is set
+}
+
+bool utf8AdvanceCodePoint(const char *&current)
+{
+ if (Q_UNLIKELY(*current == '\0'))
+ return false;
+
+ // Process multi-byte UTF-8 code point (non-latin1)
+ if (Q_UNLIKELY(isByteOfMultiByteCodePoint(*current))) {
+ unsigned trailingBytesCurrentCodePoint = 1;
+ for (unsigned char c = (*current) << 2; isByteOfMultiByteCodePoint(c); c <<= 1)
+ ++trailingBytesCurrentCodePoint;
+ current += trailingBytesCurrentCodePoint + 1;
+
+ // Process single-byte UTF-8 code point (latin1)
+ } else {
+ ++current;
+ }
+
+ return true;
+}
+
+QDebug &operator<<(QDebug &stream, const Position &pos)
+{
+ stream << "line: " << pos.line << ", column: " << pos.column;
+ return stream;
+}
+
+} // namespace Utils::Text
diff --git a/src/shared/lsp/textutils.h b/src/shared/lsp/textutils.h
new file mode 100644
index 000000000..bf4ae083f
--- /dev/null
+++ b/src/shared/lsp/textutils.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <QMetaType>
+#include <QString>
+
+namespace lsp::Utils::Text {
+
+class Position
+{
+public:
+ int line = 0; // 1-based
+ int column = -1; // 0-based
+
+ bool operator<(const Position &other) const
+ { return line < other.line || (line == other.line && column < other.column); }
+ bool operator==(const Position &other) const;
+
+ bool operator!=(const Position &other) const { return !(operator==(other)); }
+
+ bool isValid() const { return line > 0 && column >= 0; }
+
+ static Position fromFileName(QStringView fileName, int &postfixPos);
+};
+
+class Range
+{
+public:
+ int length(const QString &text) const;
+
+ Position begin;
+ Position end;
+
+ bool operator<(const Range &other) const { return begin < other.begin; }
+ bool operator==(const Range &other) const;
+
+ bool operator!=(const Range &other) const { return !(operator==(other)); }
+};
+
+QString utf16LineTextInUtf8Buffer(const QByteArray &utf8Buffer, int currentUtf8Offset);
+
+QDebug &operator<<(QDebug &stream, const Position &pos);
+
+} // Text
diff --git a/src/shared/lsp/workspace.cpp b/src/shared/lsp/workspace.cpp
new file mode 100644
index 000000000..e653bf96b
--- /dev/null
+++ b/src/shared/lsp/workspace.cpp
@@ -0,0 +1,82 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "workspace.h"
+
+namespace lsp {
+
+constexpr const char WorkSpaceFolderRequest::methodName[];
+constexpr const char DidChangeWorkspaceFoldersNotification::methodName[];
+constexpr const char DidChangeConfigurationNotification::methodName[];
+constexpr const char ConfigurationRequest::methodName[];
+constexpr const char WorkspaceSymbolRequest::methodName[];
+constexpr const char ExecuteCommandRequest::methodName[];
+constexpr const char ApplyWorkspaceEditRequest::methodName[];
+constexpr const char DidChangeWatchedFilesNotification::methodName[];
+
+WorkSpaceFolderRequest::WorkSpaceFolderRequest()
+ : Request(methodName, nullptr)
+{ }
+
+DidChangeWorkspaceFoldersNotification::DidChangeWorkspaceFoldersNotification(
+ const DidChangeWorkspaceFoldersParams &params)
+ : Notification(methodName, params)
+{ }
+
+DidChangeConfigurationNotification::DidChangeConfigurationNotification(
+ const DidChangeConfigurationParams &params)
+ : Notification(methodName, params)
+{ }
+
+ConfigurationRequest::ConfigurationRequest(const ConfigurationParams &params)
+ : Request(methodName, params)
+{ }
+
+WorkspaceSymbolRequest::WorkspaceSymbolRequest(const WorkspaceSymbolParams &params)
+ : Request(methodName, params)
+{ }
+
+ExecuteCommandRequest::ExecuteCommandRequest(const ExecuteCommandParams &params)
+ : Request(methodName, params)
+{ }
+
+ApplyWorkspaceEditRequest::ApplyWorkspaceEditRequest(const ApplyWorkspaceEditParams &params)
+ : Request(methodName, params)
+{ }
+
+WorkspaceFoldersChangeEvent::WorkspaceFoldersChangeEvent()
+{
+ insert(addedKey, QJsonArray());
+ insert(removedKey, QJsonArray());
+}
+
+DidChangeWatchedFilesNotification::DidChangeWatchedFilesNotification(
+ const DidChangeWatchedFilesParams &params)
+ : Notification(methodName, params)
+{ }
+
+ExecuteCommandParams::ExecuteCommandParams(const Command &command)
+{
+ setCommand(command.command());
+ if (command.arguments().has_value())
+ setArguments(*command.arguments());
+}
+
+WorkSpaceFolderResult::operator const QJsonValue() const
+{
+ if (!std::holds_alternative<QList<WorkSpaceFolder>>(*this))
+ return QJsonValue::Null;
+ QJsonArray array;
+ for (const auto &folder : std::get<QList<WorkSpaceFolder>>(*this))
+ array.append(QJsonValue(folder));
+ return array;
+}
+
+std::optional<DocumentUri> ConfigurationParams::ConfigurationItem::scopeUri() const
+{
+ if (const std::optional<QString> optionalScope = optionalValue<QString>(scopeUriKey))
+ return std::make_optional(DocumentUri::fromProtocol(*optionalScope));
+ return std::nullopt;
+}
+
+} // namespace lsp
diff --git a/src/shared/lsp/workspace.h b/src/shared/lsp/workspace.h
new file mode 100644
index 000000000..ffd37c1e6
--- /dev/null
+++ b/src/shared/lsp/workspace.h
@@ -0,0 +1,245 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "jsonrpcmessages.h"
+
+namespace lsp {
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkSpaceFolderResult
+ : public std::variant<QList<WorkSpaceFolder>, std::nullptr_t>
+{
+public:
+ using variant::variant;
+ using variant::operator=;
+ operator const QJsonValue() const;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkSpaceFolderRequest : public Request<
+ WorkSpaceFolderResult, std::nullptr_t, std::nullptr_t>
+{
+public:
+ WorkSpaceFolderRequest();
+ using Request::Request;
+ constexpr static const char methodName[] = "workspace/workspaceFolders";
+
+ bool parametersAreValid(QString * /*errorMessage*/) const override { return true; }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkspaceFoldersChangeEvent : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+ WorkspaceFoldersChangeEvent();
+
+ QList<WorkSpaceFolder> added() const { return array<WorkSpaceFolder>(addedKey); }
+ void setAdded(const QList<WorkSpaceFolder> &added) { insertArray(addedKey, added); }
+
+ QList<WorkSpaceFolder> removed() const { return array<WorkSpaceFolder>(removedKey); }
+ void setRemoved(const QList<WorkSpaceFolder> &removed) { insertArray(removedKey, removed); }
+
+ bool isValid() const override { return contains(addedKey) && contains(removedKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DidChangeWorkspaceFoldersParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ WorkspaceFoldersChangeEvent event() const
+ { return typedValue<WorkspaceFoldersChangeEvent>(eventKey); }
+ void setEvent(const WorkspaceFoldersChangeEvent &event) { insert(eventKey, event); }
+
+ bool isValid() const override { return contains(eventKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DidChangeWorkspaceFoldersNotification : public Notification<
+ DidChangeWorkspaceFoldersParams>
+{
+public:
+ explicit DidChangeWorkspaceFoldersNotification(const DidChangeWorkspaceFoldersParams &params);
+ constexpr static const char methodName[] = "workspace/didChangeWorkspaceFolders";
+ using Notification::Notification;
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DidChangeConfigurationParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ QJsonValue settings() const { return value(settingsKey); }
+ void setSettings(QJsonValue settings) { insert(settingsKey, settings); }
+
+ bool isValid() const override { return contains(settingsKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DidChangeConfigurationNotification : public Notification<
+ DidChangeConfigurationParams>
+{
+public:
+ explicit DidChangeConfigurationNotification(const DidChangeConfigurationParams &params);
+ using Notification::Notification;
+ constexpr static const char methodName[] = "workspace/didChangeConfiguration";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ConfigurationParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+ class LANGUAGESERVERPROTOCOL_EXPORT ConfigurationItem : public JsonObject
+ {
+ public:
+ using JsonObject::JsonObject;
+
+ std::optional<DocumentUri> scopeUri() const;
+ void setScopeUri(const DocumentUri &scopeUri) { insert(scopeUriKey, scopeUri); }
+ void clearScopeUri() { remove(scopeUriKey); }
+
+ std::optional<QString> section() const { return optionalValue<QString>(sectionKey); }
+ void setSection(const QString &section) { insert(sectionKey, section); }
+ void clearSection() { remove(sectionKey); }
+
+ bool isValid() const override { return contains(scopeUriKey); }
+ };
+
+ QList<ConfigurationItem> items() const { return array<ConfigurationItem>(itemsKey); }
+ void setItems(const QList<ConfigurationItem> &items) { insertArray(itemsKey, items); }
+
+ bool isValid() const override { return contains(itemsKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ConfigurationRequest
+ : public Request<QJsonArray, std::nullptr_t, ConfigurationParams>
+{
+public:
+ explicit ConfigurationRequest(const ConfigurationParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "workspace/configuration";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DidChangeWatchedFilesParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ class FileEvent : public JsonObject
+ {
+ public:
+ using JsonObject::JsonObject;
+
+ DocumentUri uri() const { return DocumentUri::fromProtocol(typedValue<QString>(uriKey)); }
+ void setUri(const DocumentUri &uri) { insert(uriKey, uri); }
+
+ int type() const { return typedValue<int>(typeKey); }
+ void setType(int type) { insert(typeKey, type); }
+
+ enum FileChangeType {
+ Created = 1,
+ Changed = 2,
+ Deleted = 3
+ };
+
+ bool isValid() const override { return contains(uriKey) && contains(typeKey); }
+ };
+
+ QList<FileEvent> changes() const { return array<FileEvent>(changesKey); }
+ void setChanges(const QList<FileEvent> &changes) { insertArray(changesKey, changes); }
+
+ bool isValid() const override { return contains(changesKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT DidChangeWatchedFilesNotification : public Notification<
+ DidChangeWatchedFilesParams>
+{
+public:
+ explicit DidChangeWatchedFilesNotification(const DidChangeWatchedFilesParams &params);
+ using Notification::Notification;
+ constexpr static const char methodName[] = "workspace/didChangeWatchedFiles";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkspaceSymbolParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ QString query() const { return typedValue<QString>(queryKey); }
+ void setQuery(const QString &query) { insert(queryKey, query); }
+
+ void setLimit(int limit) { insert("limit", limit); } // clangd extension
+
+ bool isValid() const override { return contains(queryKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT WorkspaceSymbolRequest : public Request<
+ LanguageClientArray<SymbolInformation>, std::nullptr_t, WorkspaceSymbolParams>
+{
+public:
+ explicit WorkspaceSymbolRequest(const WorkspaceSymbolParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "workspace/symbol";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ExecuteCommandParams : public JsonObject
+{
+public:
+ explicit ExecuteCommandParams(const Command &command);
+ explicit ExecuteCommandParams(const QJsonValue &value) : JsonObject(value) {}
+ ExecuteCommandParams() : JsonObject() {}
+
+ QString command() const { return typedValue<QString>(commandKey); }
+ void setCommand(const QString &command) { insert(commandKey, command); }
+ void clearCommand() { remove(commandKey); }
+
+ std::optional<QJsonArray> arguments() const { return typedValue<QJsonArray>(argumentsKey); }
+ void setArguments(const QJsonArray &arguments) { insert(argumentsKey, arguments); }
+ void clearArguments() { remove(argumentsKey); }
+
+ bool isValid() const override { return contains(commandKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ExecuteCommandRequest : public Request<
+ QJsonValue, std::nullptr_t, ExecuteCommandParams>
+{
+public:
+ explicit ExecuteCommandRequest(const ExecuteCommandParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "workspace/executeCommand";
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ApplyWorkspaceEditParams : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ std::optional<QString> label() const { return optionalValue<QString>(labelKey); }
+ void setLabel(const QString &label) { insert(labelKey, label); }
+ void clearLabel() { remove(labelKey); }
+
+ WorkspaceEdit edit() const { return typedValue<WorkspaceEdit>(editKey); }
+ void setEdit(const WorkspaceEdit &edit) { insert(editKey, edit); }
+
+ bool isValid() const override { return contains(editKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ApplyWorkspaceEditResult : public JsonObject
+{
+public:
+ using JsonObject::JsonObject;
+
+ bool applied() const { return typedValue<bool>(appliedKey); }
+ void setApplied(bool applied) { insert(appliedKey, applied); }
+
+ bool isValid() const override { return contains(appliedKey); }
+};
+
+class LANGUAGESERVERPROTOCOL_EXPORT ApplyWorkspaceEditRequest : public Request<
+ ApplyWorkspaceEditResult, std::nullptr_t, ApplyWorkspaceEditParams>
+{
+public:
+ explicit ApplyWorkspaceEditRequest(const ApplyWorkspaceEditParams &params);
+ using Request::Request;
+ constexpr static const char methodName[] = "workspace/applyEdit";
+};
+
+} // namespace LanguageClient
diff --git a/src/shared/quickjs/.clang-format b/src/shared/quickjs/.clang-format
new file mode 100644
index 000000000..47a38a93f
--- /dev/null
+++ b/src/shared/quickjs/.clang-format
@@ -0,0 +1,2 @@
+DisableFormat: true
+SortIncludes: Never
diff --git a/src/shared/quickjs/.clang-tidy b/src/shared/quickjs/.clang-tidy
index c5e5db244..b9209aae5 100644
--- a/src/shared/quickjs/.clang-tidy
+++ b/src/shared/quickjs/.clang-tidy
@@ -1,13 +1,3 @@
----
-Checks: >
- -bugprone-branch-clone,
- -bugprone-easily-swappable-parameters,
- -bugprone-implicit-widening-of-multiplication-result,
- -bugprone-signed-char-misuse,
- -bugprone-suspicious-memory-comparison,
- -bugprone-sizeof-expression,
- -misc-redundant-expression,
- -misc-unused-parameters
+Checks: '-*,misc-definitions-in-headers'
InheritParentConfig: true
-...
diff --git a/src/shared/quickjs/CMakeLists.txt b/src/shared/quickjs/CMakeLists.txt
index a0af03c79..d88739ab0 100644
--- a/src/shared/quickjs/CMakeLists.txt
+++ b/src/shared/quickjs/CMakeLists.txt
@@ -2,6 +2,7 @@ add_qbs_library(qbsquickjs
STATIC
SOURCES
cutils.c cutils.h
+ libbf.c libbf.h
libregexp-opcode.h
libregexp.c libregexp.h
libunicode-table.h
diff --git a/src/shared/quickjs/LICENSE b/src/shared/quickjs/LICENSE
index 2c8fdebaf..2cf449dd3 100644
--- a/src/shared/quickjs/LICENSE
+++ b/src/shared/quickjs/LICENSE
@@ -1,5 +1,5 @@
QuickJS Javascript Engine
-
+
Copyright (c) 2017-2021 Fabrice Bellard
Copyright (c) 2017-2021 Charlie Gordon
diff --git a/src/shared/quickjs/cutils.c b/src/shared/quickjs/cutils.c
index 1f66fff3f..95ae5688d 100644
--- a/src/shared/quickjs/cutils.c
+++ b/src/shared/quickjs/cutils.c
@@ -1,6 +1,6 @@
/*
* C utilities
- *
+ *
* Copyright (c) 2017 Fabrice Bellard
* Copyright (c) 2018 Charlie Gordon
*
@@ -140,7 +140,7 @@ int dbuf_put(DynBuf *s, const uint8_t *data, size_t len)
if (dbuf_realloc(s, s->size + len))
return -1;
}
- memcpy(s->buf + s->size, data, len);
+ memcpy_no_ub(s->buf + s->size, data, len);
s->size += len;
return 0;
}
@@ -171,7 +171,7 @@ int FORMAT_ATTR(2, 3) dbuf_printf(DynBuf *s, const char *fmt, ...)
va_list ap;
char buf[128];
int len;
-
+
va_start(ap, fmt);
len = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
diff --git a/src/shared/quickjs/cutils.h b/src/shared/quickjs/cutils.h
index ee0ce4a2e..265fd0aee 100644
--- a/src/shared/quickjs/cutils.h
+++ b/src/shared/quickjs/cutils.h
@@ -26,6 +26,7 @@
#define CUTILS_H
#include <stdlib.h>
+#include <string.h>
#include <inttypes.h>
#if defined(_MSC_VER)
@@ -35,21 +36,18 @@ typedef SSIZE_T ssize_t;
#include <sys/types.h>
#endif
-/* set if CPU is big endian */
-#undef WORDS_BIGENDIAN
-
#ifdef __GNUC__
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#define force_inline inline __attribute__((always_inline))
#define no_inline __attribute__((noinline))
-#define maybe_unused __attribute__((unused))
+#define __maybe_unused __attribute__((unused))
#else
#define likely(x) (x)
#define unlikely(x) (x)
#define force_inline
#define no_inline
-#define maybe_unused
+#define __maybe_unused
#endif
#ifdef _MSC_VER
@@ -67,6 +65,16 @@ typedef SSIZE_T ssize_t;
#ifndef countof
#define countof(x) (sizeof(x) / sizeof((x)[0]))
#endif
+#ifndef container_of
+/* return the pointer of type 'type *' containing 'ptr' as field 'member' */
+#define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member)))
+#endif
+
+#if !defined(_MSC_VER) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define minimum_length(n) static n
+#else
+#define minimum_length(n) n
+#endif
typedef int BOOL;
@@ -82,6 +90,12 @@ char *pstrcat(char *buf, int buf_size, const char *s);
int strstart(const char *str, const char *val, const char **ptr);
int has_suffix(const char *str, const char *suffix);
+/* Prevent UB when n == 0 and (src == NULL or dest == NULL) */
+static inline void memcpy_no_ub(void *dest, const void *src, size_t n) {
+ if (n)
+ memcpy(dest, src, n);
+}
+
static inline int max_int(int a, int b)
{
if (a > b)
@@ -140,6 +154,36 @@ static inline int clz32(unsigned int a)
#endif
}
+/* WARNING: undefined if a = 0 */
+static inline int clz64(uint64_t a)
+{
+#ifdef _MSC_VER
+ return (int) __lzcnt64(a);
+#else
+ return __builtin_clzll(a);
+#endif
+}
+
+/* WARNING: undefined if a = 0 */
+static inline int ctz32(unsigned int a)
+{
+#ifdef _MSC_VER
+ return (int) _tzcnt_u32(a);
+#else
+ return __builtin_ctz(a);
+#endif
+}
+
+/* WARNING: undefined if a = 0 */
+static inline int ctz64(uint64_t a)
+{
+#ifdef _MSC_VER
+ return (int) _tzcnt_u64(a);
+#else
+ return __builtin_ctzll(a);
+#endif
+}
+
#pragma pack(push, 1)
struct packed_u64 {
uint64_t v;
@@ -212,17 +256,22 @@ static inline void put_u8(uint8_t *tab, uint8_t val)
*tab = val;
}
+#ifndef bswap16
static inline uint16_t bswap16(uint16_t x)
{
return (x >> 8) | (x << 8);
}
+#endif
+#ifndef bswap32
static inline uint32_t bswap32(uint32_t v)
{
return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) |
((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24);
}
+#endif
+#ifndef bswap64
static inline uint64_t bswap64(uint64_t v)
{
return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) |
@@ -234,6 +283,7 @@ static inline uint64_t bswap64(uint64_t v)
((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) |
((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8));
}
+#endif
/* XXX: should take an extra argument to pass slack information to the caller */
typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size);
@@ -290,6 +340,36 @@ static inline void dbuf_set_error(DynBuf *s)
int unicode_to_utf8(uint8_t *buf, unsigned int c);
int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp);
+static inline BOOL is_surrogate(uint32_t c)
+{
+ return (c >> 11) == (0xD800 >> 11); // 0xD800-0xDFFF
+}
+
+static inline BOOL is_hi_surrogate(uint32_t c)
+{
+ return (c >> 10) == (0xD800 >> 10); // 0xD800-0xDBFF
+}
+
+static inline BOOL is_lo_surrogate(uint32_t c)
+{
+ return (c >> 10) == (0xDC00 >> 10); // 0xDC00-0xDFFF
+}
+
+static inline uint32_t get_hi_surrogate(uint32_t c)
+{
+ return (c >> 10) - (0x10000 >> 10) + 0xD800;
+}
+
+static inline uint32_t get_lo_surrogate(uint32_t c)
+{
+ return (c & 0x3FF) | 0xDC00;
+}
+
+static inline uint32_t from_surrogate(uint32_t hi, uint32_t lo)
+{
+ return 0x10000 + 0x400 * (hi - 0xD800) + (lo - 0xDC00);
+}
+
static inline int from_hex(int c)
{
if (c >= '0' && c <= '9')
diff --git a/src/shared/quickjs/libbf.c b/src/shared/quickjs/libbf.c
new file mode 100644
index 000000000..56b2be861
--- /dev/null
+++ b/src/shared/quickjs/libbf.c
@@ -0,0 +1,8475 @@
+/*
+ * Tiny arbitrary precision floating point library
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <math.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef __AVX2__
+#include <immintrin.h>
+#endif
+
+#include "cutils.h"
+#include "libbf.h"
+
+/* enable it to check the multiplication result */
+//#define USE_MUL_CHECK
+/* enable it to use FFT/NTT multiplication */
+#define USE_FFT_MUL
+/* enable decimal floating point support */
+#define USE_BF_DEC
+
+//#define inline __attribute__((always_inline))
+
+#ifdef __AVX2__
+#define FFT_MUL_THRESHOLD 100 /* in limbs of the smallest factor */
+#else
+#define FFT_MUL_THRESHOLD 100 /* in limbs of the smallest factor */
+#endif
+
+/* XXX: adjust */
+#define DIVNORM_LARGE_THRESHOLD 50
+#define UDIV1NORM_THRESHOLD 3
+
+#if LIMB_BITS == 64
+#define FMT_LIMB1 "%" PRIx64
+#define FMT_LIMB "%016" PRIx64
+#define PRId_LIMB PRId64
+#define PRIu_LIMB PRIu64
+
+#else
+
+#define FMT_LIMB1 "%x"
+#define FMT_LIMB "%08x"
+#define PRId_LIMB "d"
+#define PRIu_LIMB "u"
+
+#endif
+
+typedef intptr_t mp_size_t;
+
+typedef int bf_op2_func_t(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
+ bf_flags_t flags);
+
+#ifdef USE_FFT_MUL
+
+#define FFT_MUL_R_OVERLAP_A (1 << 0)
+#define FFT_MUL_R_OVERLAP_B (1 << 1)
+#define FFT_MUL_R_NORESIZE (1 << 2)
+
+static no_inline int fft_mul(bf_context_t *s,
+ bf_t *res, limb_t *a_tab, limb_t a_len,
+ limb_t *b_tab, limb_t b_len, int mul_flags);
+static void fft_clear_cache(bf_context_t *s);
+#endif
+#ifdef USE_BF_DEC
+static limb_t get_digit(const limb_t *tab, limb_t len, slimb_t pos);
+#endif
+
+
+/* could leading zeros */
+static inline int clz(limb_t a)
+{
+ if (a == 0) {
+ return LIMB_BITS;
+ } else {
+#if LIMB_BITS == 64
+ return clz64(a);
+#else
+ return clz32(a);
+#endif
+ }
+}
+
+static inline int ctz(limb_t a)
+{
+ if (a == 0) {
+ return LIMB_BITS;
+ } else {
+#if LIMB_BITS == 64
+ return ctz64(a);
+#else
+ return ctz32(a);
+#endif
+ }
+}
+
+static inline int ceil_log2(limb_t a)
+{
+ if (a <= 1)
+ return 0;
+ else
+ return LIMB_BITS - clz(a - 1);
+}
+
+/* b must be >= 1 */
+static inline slimb_t ceil_div(slimb_t a, slimb_t b)
+{
+ if (a >= 0)
+ return (a + b - 1) / b;
+ else
+ return a / b;
+}
+
+#ifdef USE_BF_DEC
+/* b must be >= 1 */
+static inline slimb_t floor_div(slimb_t a, slimb_t b)
+{
+ if (a >= 0) {
+ return a / b;
+ } else {
+ return (a - b + 1) / b;
+ }
+}
+#endif
+
+/* return r = a modulo b (0 <= r <= b - 1. b must be >= 1 */
+static inline limb_t smod(slimb_t a, slimb_t b)
+{
+ a = a % (slimb_t)b;
+ if (a < 0)
+ a += b;
+ return a;
+}
+
+/* signed addition with saturation */
+static inline slimb_t sat_add(slimb_t a, slimb_t b)
+{
+ slimb_t r;
+ r = a + b;
+ /* overflow ? */
+ if (((a ^ r) & (b ^ r)) < 0)
+ r = (a >> (LIMB_BITS - 1)) ^ (((limb_t)1 << (LIMB_BITS - 1)) - 1);
+ return r;
+}
+
+static inline __maybe_unused limb_t shrd(limb_t low, limb_t high, long shift)
+{
+ if (shift != 0)
+ low = (low >> shift) | (high << (LIMB_BITS - shift));
+ return low;
+}
+
+static inline __maybe_unused limb_t shld(limb_t a1, limb_t a0, long shift)
+{
+ if (shift != 0)
+ return (a1 << shift) | (a0 >> (LIMB_BITS - shift));
+ else
+ return a1;
+}
+
+#define malloc(s) malloc_is_forbidden(s)
+#define free(p) free_is_forbidden(p)
+#define realloc(p, s) realloc_is_forbidden(p, s)
+
+void bf_context_init(bf_context_t *s, bf_realloc_func_t *realloc_func,
+ void *realloc_opaque)
+{
+ memset(s, 0, sizeof(*s));
+ s->realloc_func = realloc_func;
+ s->realloc_opaque = realloc_opaque;
+}
+
+void bf_context_end(bf_context_t *s)
+{
+ bf_clear_cache(s);
+}
+
+void bf_init(bf_context_t *s, bf_t *r)
+{
+ r->ctx = s;
+ r->sign = 0;
+ r->expn = BF_EXP_ZERO;
+ r->len = 0;
+ r->tab = NULL;
+}
+
+/* return 0 if OK, -1 if alloc error */
+int bf_resize(bf_t *r, limb_t len)
+{
+ limb_t *tab;
+
+ if (len != r->len) {
+ tab = bf_realloc(r->ctx, r->tab, len * sizeof(limb_t));
+ if (!tab && len != 0)
+ return -1;
+ r->tab = tab;
+ r->len = len;
+ }
+ return 0;
+}
+
+/* return 0 or BF_ST_MEM_ERROR */
+int bf_set_ui(bf_t *r, uint64_t a)
+{
+ r->sign = 0;
+ if (a == 0) {
+ r->expn = BF_EXP_ZERO;
+ bf_resize(r, 0); /* cannot fail */
+ }
+#if LIMB_BITS == 32
+ else if (a <= 0xffffffff)
+#else
+ else
+#endif
+ {
+ int shift;
+ if (bf_resize(r, 1))
+ goto fail;
+ shift = clz(a);
+ r->tab[0] = a << shift;
+ r->expn = LIMB_BITS - shift;
+ }
+#if LIMB_BITS == 32
+ else {
+ uint32_t a1, a0;
+ int shift;
+ if (bf_resize(r, 2))
+ goto fail;
+ a0 = a;
+ a1 = a >> 32;
+ shift = clz(a1);
+ r->tab[0] = a0 << shift;
+ r->tab[1] = shld(a1, a0, shift);
+ r->expn = 2 * LIMB_BITS - shift;
+ }
+#endif
+ return 0;
+ fail:
+ bf_set_nan(r);
+ return BF_ST_MEM_ERROR;
+}
+
+/* return 0 or BF_ST_MEM_ERROR */
+int bf_set_si(bf_t *r, int64_t a)
+{
+ int ret;
+
+ if (a < 0) {
+ ret = bf_set_ui(r, -a);
+ r->sign = 1;
+ } else {
+ ret = bf_set_ui(r, a);
+ }
+ return ret;
+}
+
+void bf_set_nan(bf_t *r)
+{
+ bf_resize(r, 0); /* cannot fail */
+ r->expn = BF_EXP_NAN;
+ r->sign = 0;
+}
+
+void bf_set_zero(bf_t *r, int is_neg)
+{
+ bf_resize(r, 0); /* cannot fail */
+ r->expn = BF_EXP_ZERO;
+ r->sign = is_neg;
+}
+
+void bf_set_inf(bf_t *r, int is_neg)
+{
+ bf_resize(r, 0); /* cannot fail */
+ r->expn = BF_EXP_INF;
+ r->sign = is_neg;
+}
+
+/* return 0 or BF_ST_MEM_ERROR */
+int bf_set(bf_t *r, const bf_t *a)
+{
+ if (r == a)
+ return 0;
+ if (bf_resize(r, a->len)) {
+ bf_set_nan(r);
+ return BF_ST_MEM_ERROR;
+ }
+ r->sign = a->sign;
+ r->expn = a->expn;
+ memcpy_no_ub(r->tab, a->tab, a->len * sizeof(limb_t));
+ return 0;
+}
+
+/* equivalent to bf_set(r, a); bf_delete(a) */
+void bf_move(bf_t *r, bf_t *a)
+{
+ bf_context_t *s = r->ctx;
+ if (r == a)
+ return;
+ bf_free(s, r->tab);
+ *r = *a;
+}
+
+static limb_t get_limbz(const bf_t *a, limb_t idx)
+{
+ if (idx >= a->len)
+ return 0;
+ else
+ return a->tab[idx];
+}
+
+/* get LIMB_BITS at bit position 'pos' in tab */
+static inline limb_t get_bits(const limb_t *tab, limb_t len, slimb_t pos)
+{
+ limb_t i, a0, a1;
+ int p;
+
+ i = pos >> LIMB_LOG2_BITS;
+ p = pos & (LIMB_BITS - 1);
+ if (i < len)
+ a0 = tab[i];
+ else
+ a0 = 0;
+ if (p == 0) {
+ return a0;
+ } else {
+ i++;
+ if (i < len)
+ a1 = tab[i];
+ else
+ a1 = 0;
+ return (a0 >> p) | (a1 << (LIMB_BITS - p));
+ }
+}
+
+static inline limb_t get_bit(const limb_t *tab, limb_t len, slimb_t pos)
+{
+ slimb_t i;
+ i = pos >> LIMB_LOG2_BITS;
+ if (i < 0 || i >= len)
+ return 0;
+ return (tab[i] >> (pos & (LIMB_BITS - 1))) & 1;
+}
+
+static inline limb_t limb_mask(int start, int last)
+{
+ limb_t v;
+ int n;
+ n = last - start + 1;
+ if (n == LIMB_BITS)
+ v = -1;
+ else
+ v = (((limb_t)1 << n) - 1) << start;
+ return v;
+}
+
+static limb_t mp_scan_nz(const limb_t *tab, mp_size_t n)
+{
+ mp_size_t i;
+ for(i = 0; i < n; i++) {
+ if (tab[i] != 0)
+ return 1;
+ }
+ return 0;
+}
+
+/* return != 0 if one bit between 0 and bit_pos inclusive is not zero. */
+static inline limb_t scan_bit_nz(const bf_t *r, slimb_t bit_pos)
+{
+ slimb_t pos;
+ limb_t v;
+
+ pos = bit_pos >> LIMB_LOG2_BITS;
+ if (pos < 0)
+ return 0;
+ v = r->tab[pos] & limb_mask(0, bit_pos & (LIMB_BITS - 1));
+ if (v != 0)
+ return 1;
+ pos--;
+ while (pos >= 0) {
+ if (r->tab[pos] != 0)
+ return 1;
+ pos--;
+ }
+ return 0;
+}
+
+/* return the addend for rounding. Note that prec can be <= 0 (for
+ BF_FLAG_RADPNT_PREC) */
+static int bf_get_rnd_add(int *pret, const bf_t *r, limb_t l,
+ slimb_t prec, int rnd_mode)
+{
+ int add_one, inexact;
+ limb_t bit1, bit0;
+
+ if (rnd_mode == BF_RNDF) {
+ bit0 = 1; /* faithful rounding does not honor the INEXACT flag */
+ } else {
+ /* starting limb for bit 'prec + 1' */
+ bit0 = scan_bit_nz(r, l * LIMB_BITS - 1 - bf_max(0, prec + 1));
+ }
+
+ /* get the bit at 'prec' */
+ bit1 = get_bit(r->tab, l, l * LIMB_BITS - 1 - prec);
+ inexact = (bit1 | bit0) != 0;
+
+ add_one = 0;
+ switch(rnd_mode) {
+ case BF_RNDZ:
+ break;
+ case BF_RNDN:
+ if (bit1) {
+ if (bit0) {
+ add_one = 1;
+ } else {
+ /* round to even */
+ add_one =
+ get_bit(r->tab, l, l * LIMB_BITS - 1 - (prec - 1));
+ }
+ }
+ break;
+ case BF_RNDD:
+ case BF_RNDU:
+ if (r->sign == (rnd_mode == BF_RNDD))
+ add_one = inexact;
+ break;
+ case BF_RNDA:
+ add_one = inexact;
+ break;
+ case BF_RNDNA:
+ case BF_RNDF:
+ add_one = bit1;
+ break;
+ default:
+ abort();
+ }
+
+ if (inexact)
+ *pret |= BF_ST_INEXACT;
+ return add_one;
+}
+
+static int bf_set_overflow(bf_t *r, int sign, limb_t prec, bf_flags_t flags)
+{
+ slimb_t i, l, e_max;
+ int rnd_mode;
+
+ rnd_mode = flags & BF_RND_MASK;
+ if (prec == BF_PREC_INF ||
+ rnd_mode == BF_RNDN ||
+ rnd_mode == BF_RNDNA ||
+ rnd_mode == BF_RNDA ||
+ (rnd_mode == BF_RNDD && sign == 1) ||
+ (rnd_mode == BF_RNDU && sign == 0)) {
+ bf_set_inf(r, sign);
+ } else {
+ /* set to maximum finite number */
+ l = (prec + LIMB_BITS - 1) / LIMB_BITS;
+ if (bf_resize(r, l)) {
+ bf_set_nan(r);
+ return BF_ST_MEM_ERROR;
+ }
+ r->tab[0] = limb_mask((-prec) & (LIMB_BITS - 1),
+ LIMB_BITS - 1);
+ for(i = 1; i < l; i++)
+ r->tab[i] = (limb_t)-1;
+ e_max = (limb_t)1 << (bf_get_exp_bits(flags) - 1);
+ r->expn = e_max;
+ r->sign = sign;
+ }
+ return BF_ST_OVERFLOW | BF_ST_INEXACT;
+}
+
+/* round to prec1 bits assuming 'r' is non zero and finite. 'r' is
+ assumed to have length 'l' (1 <= l <= r->len). Note: 'prec1' can be
+ infinite (BF_PREC_INF). 'ret' is 0 or BF_ST_INEXACT if the result
+ is known to be inexact. Can fail with BF_ST_MEM_ERROR in case of
+ overflow not returning infinity. */
+static int __bf_round(bf_t *r, limb_t prec1, bf_flags_t flags, limb_t l,
+ int ret)
+{
+ limb_t v, a;
+ int shift, add_one, rnd_mode;
+ slimb_t i, bit_pos, pos, e_min, e_max, e_range, prec;
+
+ /* e_min and e_max are computed to match the IEEE 754 conventions */
+ e_range = (limb_t)1 << (bf_get_exp_bits(flags) - 1);
+ e_min = -e_range + 3;
+ e_max = e_range;
+
+ if (flags & BF_FLAG_RADPNT_PREC) {
+ /* 'prec' is the precision after the radix point */
+ if (prec1 != BF_PREC_INF)
+ prec = r->expn + prec1;
+ else
+ prec = prec1;
+ } else if (unlikely(r->expn < e_min) && (flags & BF_FLAG_SUBNORMAL)) {
+ /* restrict the precision in case of potentially subnormal
+ result */
+ assert(prec1 != BF_PREC_INF);
+ prec = prec1 - (e_min - r->expn);
+ } else {
+ prec = prec1;
+ }
+
+ /* round to prec bits */
+ rnd_mode = flags & BF_RND_MASK;
+ add_one = bf_get_rnd_add(&ret, r, l, prec, rnd_mode);
+
+ if (prec <= 0) {
+ if (add_one) {
+ bf_resize(r, 1); /* cannot fail */
+ r->tab[0] = (limb_t)1 << (LIMB_BITS - 1);
+ r->expn += 1 - prec;
+ ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;
+ return ret;
+ } else {
+ goto underflow;
+ }
+ } else if (add_one) {
+ limb_t carry;
+
+ /* add one starting at digit 'prec - 1' */
+ bit_pos = l * LIMB_BITS - 1 - (prec - 1);
+ pos = bit_pos >> LIMB_LOG2_BITS;
+ carry = (limb_t)1 << (bit_pos & (LIMB_BITS - 1));
+
+ for(i = pos; i < l; i++) {
+ v = r->tab[i] + carry;
+ carry = (v < carry);
+ r->tab[i] = v;
+ if (carry == 0)
+ break;
+ }
+ if (carry) {
+ /* shift right by one digit */
+ v = 1;
+ for(i = l - 1; i >= pos; i--) {
+ a = r->tab[i];
+ r->tab[i] = (a >> 1) | (v << (LIMB_BITS - 1));
+ v = a;
+ }
+ r->expn++;
+ }
+ }
+
+ /* check underflow */
+ if (unlikely(r->expn < e_min)) {
+ if (flags & BF_FLAG_SUBNORMAL) {
+ /* if inexact, also set the underflow flag */
+ if (ret & BF_ST_INEXACT)
+ ret |= BF_ST_UNDERFLOW;
+ } else {
+ underflow:
+ ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;
+ bf_set_zero(r, r->sign);
+ return ret;
+ }
+ }
+
+ /* check overflow */
+ if (unlikely(r->expn > e_max))
+ return bf_set_overflow(r, r->sign, prec1, flags);
+
+ /* keep the bits starting at 'prec - 1' */
+ bit_pos = l * LIMB_BITS - 1 - (prec - 1);
+ i = bit_pos >> LIMB_LOG2_BITS;
+ if (i >= 0) {
+ shift = bit_pos & (LIMB_BITS - 1);
+ if (shift != 0)
+ r->tab[i] &= limb_mask(shift, LIMB_BITS - 1);
+ } else {
+ i = 0;
+ }
+ /* remove trailing zeros */
+ while (r->tab[i] == 0)
+ i++;
+ if (i > 0) {
+ l -= i;
+ memmove(r->tab, r->tab + i, l * sizeof(limb_t));
+ }
+ bf_resize(r, l); /* cannot fail */
+ return ret;
+}
+
+/* 'r' must be a finite number. */
+int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags)
+{
+ limb_t l, v, a;
+ int shift, ret;
+ slimb_t i;
+
+ // bf_print_str("bf_renorm", r);
+ l = r->len;
+ while (l > 0 && r->tab[l - 1] == 0)
+ l--;
+ if (l == 0) {
+ /* zero */
+ r->expn = BF_EXP_ZERO;
+ bf_resize(r, 0); /* cannot fail */
+ ret = 0;
+ } else {
+ r->expn -= (r->len - l) * LIMB_BITS;
+ /* shift to have the MSB set to '1' */
+ v = r->tab[l - 1];
+ shift = clz(v);
+ if (shift != 0) {
+ v = 0;
+ for(i = 0; i < l; i++) {
+ a = r->tab[i];
+ r->tab[i] = (a << shift) | (v >> (LIMB_BITS - shift));
+ v = a;
+ }
+ r->expn -= shift;
+ }
+ ret = __bf_round(r, prec1, flags, l, 0);
+ }
+ // bf_print_str("r_final", r);
+ return ret;
+}
+
+/* return true if rounding can be done at precision 'prec' assuming
+ the exact result r is such that |r-a| <= 2^(EXP(a)-k). */
+/* XXX: check the case where the exponent would be incremented by the
+ rounding */
+int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k)
+{
+ BOOL is_rndn;
+ slimb_t bit_pos, n;
+ limb_t bit;
+
+ if (a->expn == BF_EXP_INF || a->expn == BF_EXP_NAN)
+ return FALSE;
+ if (rnd_mode == BF_RNDF) {
+ return (k >= (prec + 1));
+ }
+ if (a->expn == BF_EXP_ZERO)
+ return FALSE;
+ is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);
+ if (k < (prec + 2))
+ return FALSE;
+ bit_pos = a->len * LIMB_BITS - 1 - prec;
+ n = k - prec;
+ /* bit pattern for RNDN or RNDNA: 0111.. or 1000...
+ for other rounding modes: 000... or 111...
+ */
+ bit = get_bit(a->tab, a->len, bit_pos);
+ bit_pos--;
+ n--;
+ bit ^= is_rndn;
+ /* XXX: slow, but a few iterations on average */
+ while (n != 0) {
+ if (get_bit(a->tab, a->len, bit_pos) != bit)
+ return TRUE;
+ bit_pos--;
+ n--;
+ }
+ return FALSE;
+}
+
+/* Cannot fail with BF_ST_MEM_ERROR. */
+int bf_round(bf_t *r, limb_t prec, bf_flags_t flags)
+{
+ if (r->len == 0)
+ return 0;
+ return __bf_round(r, prec, flags, r->len, 0);
+}
+
+/* for debugging */
+static __maybe_unused void dump_limbs(const char *str, const limb_t *tab, limb_t n)
+{
+ limb_t i;
+ printf("%s: len=%" PRId_LIMB "\n", str, n);
+ for(i = 0; i < n; i++) {
+ printf("%" PRId_LIMB ": " FMT_LIMB "\n",
+ i, tab[i]);
+ }
+}
+
+void mp_print_str(const char *str, const limb_t *tab, limb_t n)
+{
+ slimb_t i;
+ printf("%s= 0x", str);
+ for(i = n - 1; i >= 0; i--) {
+ if (i != (n - 1))
+ printf("_");
+ printf(FMT_LIMB, tab[i]);
+ }
+ printf("\n");
+}
+
+static __maybe_unused void mp_print_str_h(const char *str,
+ const limb_t *tab, limb_t n,
+ limb_t high)
+{
+ slimb_t i;
+ printf("%s= 0x", str);
+ printf(FMT_LIMB, high);
+ for(i = n - 1; i >= 0; i--) {
+ printf("_");
+ printf(FMT_LIMB, tab[i]);
+ }
+ printf("\n");
+}
+
+/* for debugging */
+void bf_print_str(const char *str, const bf_t *a)
+{
+ slimb_t i;
+ printf("%s=", str);
+
+ if (a->expn == BF_EXP_NAN) {
+ printf("NaN");
+ } else {
+ if (a->sign)
+ putchar('-');
+ if (a->expn == BF_EXP_ZERO) {
+ putchar('0');
+ } else if (a->expn == BF_EXP_INF) {
+ printf("Inf");
+ } else {
+ printf("0x0.");
+ for(i = a->len - 1; i >= 0; i--)
+ printf(FMT_LIMB, a->tab[i]);
+ printf("p%" PRId_LIMB, a->expn);
+ }
+ }
+ printf("\n");
+}
+
+/* compare the absolute value of 'a' and 'b'. Return < 0 if a < b, 0
+ if a = b and > 0 otherwise. */
+int bf_cmpu(const bf_t *a, const bf_t *b)
+{
+ slimb_t i;
+ limb_t len, v1, v2;
+
+ if (a->expn != b->expn) {
+ if (a->expn < b->expn)
+ return -1;
+ else
+ return 1;
+ }
+ len = bf_max(a->len, b->len);
+ for(i = len - 1; i >= 0; i--) {
+ v1 = get_limbz(a, a->len - len + i);
+ v2 = get_limbz(b, b->len - len + i);
+ if (v1 != v2) {
+ if (v1 < v2)
+ return -1;
+ else
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Full order: -0 < 0, NaN == NaN and NaN is larger than all other numbers */
+int bf_cmp_full(const bf_t *a, const bf_t *b)
+{
+ int res;
+
+ if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
+ if (a->expn == b->expn)
+ res = 0;
+ else if (a->expn == BF_EXP_NAN)
+ res = 1;
+ else
+ res = -1;
+ } else if (a->sign != b->sign) {
+ res = 1 - 2 * a->sign;
+ } else {
+ res = bf_cmpu(a, b);
+ if (a->sign)
+ res = -res;
+ }
+ return res;
+}
+
+/* Standard floating point comparison: return 2 if one of the operands
+ is NaN (unordered) or -1, 0, 1 depending on the ordering assuming
+ -0 == +0 */
+int bf_cmp(const bf_t *a, const bf_t *b)
+{
+ int res;
+
+ if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
+ res = 2;
+ } else if (a->sign != b->sign) {
+ if (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_ZERO)
+ res = 0;
+ else
+ res = 1 - 2 * a->sign;
+ } else {
+ res = bf_cmpu(a, b);
+ if (a->sign)
+ res = -res;
+ }
+ return res;
+}
+
+/* Compute the number of bits 'n' matching the pattern:
+ a= X1000..0
+ b= X0111..1
+
+ When computing a-b, the result will have at least n leading zero
+ bits.
+
+ Precondition: a > b and a.expn - b.expn = 0 or 1
+*/
+static limb_t count_cancelled_bits(const bf_t *a, const bf_t *b)
+{
+ slimb_t bit_offset, b_offset, n;
+ int p, p1;
+ limb_t v1, v2, mask;
+
+ bit_offset = a->len * LIMB_BITS - 1;
+ b_offset = (b->len - a->len) * LIMB_BITS - (LIMB_BITS - 1) +
+ a->expn - b->expn;
+ n = 0;
+
+ /* first search the equals bits */
+ for(;;) {
+ v1 = get_limbz(a, bit_offset >> LIMB_LOG2_BITS);
+ v2 = get_bits(b->tab, b->len, bit_offset + b_offset);
+ // printf("v1=" FMT_LIMB " v2=" FMT_LIMB "\n", v1, v2);
+ if (v1 != v2)
+ break;
+ n += LIMB_BITS;
+ bit_offset -= LIMB_BITS;
+ }
+ /* find the position of the first different bit */
+ p = clz(v1 ^ v2) + 1;
+ n += p;
+ /* then search for '0' in a and '1' in b */
+ p = LIMB_BITS - p;
+ if (p > 0) {
+ /* search in the trailing p bits of v1 and v2 */
+ mask = limb_mask(0, p - 1);
+ p1 = bf_min(clz(v1 & mask), clz((~v2) & mask)) - (LIMB_BITS - p);
+ n += p1;
+ if (p1 != p)
+ goto done;
+ }
+ bit_offset -= LIMB_BITS;
+ for(;;) {
+ v1 = get_limbz(a, bit_offset >> LIMB_LOG2_BITS);
+ v2 = get_bits(b->tab, b->len, bit_offset + b_offset);
+ // printf("v1=" FMT_LIMB " v2=" FMT_LIMB "\n", v1, v2);
+ if (v1 != 0 || v2 != -1) {
+ /* different: count the matching bits */
+ p1 = bf_min(clz(v1), clz(~v2));
+ n += p1;
+ break;
+ }
+ n += LIMB_BITS;
+ bit_offset -= LIMB_BITS;
+ }
+ done:
+ return n;
+}
+
+static int bf_add_internal(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
+ bf_flags_t flags, int b_neg)
+{
+ const bf_t *tmp;
+ int is_sub, ret, cmp_res, a_sign, b_sign;
+
+ a_sign = a->sign;
+ b_sign = b->sign ^ b_neg;
+ is_sub = a_sign ^ b_sign;
+ cmp_res = bf_cmpu(a, b);
+ if (cmp_res < 0) {
+ tmp = a;
+ a = b;
+ b = tmp;
+ a_sign = b_sign; /* b_sign is never used later */
+ }
+ /* abs(a) >= abs(b) */
+ if (cmp_res == 0 && is_sub && a->expn < BF_EXP_INF) {
+ /* zero result */
+ bf_set_zero(r, (flags & BF_RND_MASK) == BF_RNDD);
+ ret = 0;
+ } else if (a->len == 0 || b->len == 0) {
+ ret = 0;
+ if (a->expn >= BF_EXP_INF) {
+ if (a->expn == BF_EXP_NAN) {
+ /* at least one operand is NaN */
+ bf_set_nan(r);
+ } else if (b->expn == BF_EXP_INF && is_sub) {
+ /* infinities with different signs */
+ bf_set_nan(r);
+ ret = BF_ST_INVALID_OP;
+ } else {
+ bf_set_inf(r, a_sign);
+ }
+ } else {
+ /* at least one zero and not subtract */
+ bf_set(r, a);
+ r->sign = a_sign;
+ goto renorm;
+ }
+ } else {
+ slimb_t d, a_offset, b_bit_offset, i, cancelled_bits;
+ limb_t carry, v1, v2, u, r_len, carry1, precl, tot_len, z, sub_mask;
+
+ r->sign = a_sign;
+ r->expn = a->expn;
+ d = a->expn - b->expn;
+ /* must add more precision for the leading cancelled bits in
+ subtraction */
+ if (is_sub) {
+ if (d <= 1)
+ cancelled_bits = count_cancelled_bits(a, b);
+ else
+ cancelled_bits = 1;
+ } else {
+ cancelled_bits = 0;
+ }
+
+ /* add two extra bits for rounding */
+ precl = (cancelled_bits + prec + 2 + LIMB_BITS - 1) / LIMB_BITS;
+ tot_len = bf_max(a->len, b->len + (d + LIMB_BITS - 1) / LIMB_BITS);
+ r_len = bf_min(precl, tot_len);
+ if (bf_resize(r, r_len))
+ goto fail;
+ a_offset = a->len - r_len;
+ b_bit_offset = (b->len - r_len) * LIMB_BITS + d;
+
+ /* compute the bits before for the rounding */
+ carry = is_sub;
+ z = 0;
+ sub_mask = -is_sub;
+ i = r_len - tot_len;
+ while (i < 0) {
+ slimb_t ap, bp;
+ BOOL inflag;
+
+ ap = a_offset + i;
+ bp = b_bit_offset + i * LIMB_BITS;
+ inflag = FALSE;
+ if (ap >= 0 && ap < a->len) {
+ v1 = a->tab[ap];
+ inflag = TRUE;
+ } else {
+ v1 = 0;
+ }
+ if (bp + LIMB_BITS > 0 && bp < (slimb_t)(b->len * LIMB_BITS)) {
+ v2 = get_bits(b->tab, b->len, bp);
+ inflag = TRUE;
+ } else {
+ v2 = 0;
+ }
+ if (!inflag) {
+ /* outside 'a' and 'b': go directly to the next value
+ inside a or b so that the running time does not
+ depend on the exponent difference */
+ i = 0;
+ if (ap < 0)
+ i = bf_min(i, -a_offset);
+ /* b_bit_offset + i * LIMB_BITS + LIMB_BITS >= 1
+ equivalent to
+ i >= ceil(-b_bit_offset + 1 - LIMB_BITS) / LIMB_BITS)
+ */
+ if (bp + LIMB_BITS <= 0)
+ i = bf_min(i, (-b_bit_offset) >> LIMB_LOG2_BITS);
+ } else {
+ i++;
+ }
+ v2 ^= sub_mask;
+ u = v1 + v2;
+ carry1 = u < v1;
+ u += carry;
+ carry = (u < carry) | carry1;
+ z |= u;
+ }
+ /* and the result */
+ for(i = 0; i < r_len; i++) {
+ v1 = get_limbz(a, a_offset + i);
+ v2 = get_bits(b->tab, b->len, b_bit_offset + i * LIMB_BITS);
+ v2 ^= sub_mask;
+ u = v1 + v2;
+ carry1 = u < v1;
+ u += carry;
+ carry = (u < carry) | carry1;
+ r->tab[i] = u;
+ }
+ /* set the extra bits for the rounding */
+ r->tab[0] |= (z != 0);
+
+ /* carry is only possible in add case */
+ if (!is_sub && carry) {
+ if (bf_resize(r, r_len + 1))
+ goto fail;
+ r->tab[r_len] = 1;
+ r->expn += LIMB_BITS;
+ }
+ renorm:
+ ret = bf_normalize_and_round(r, prec, flags);
+ }
+ return ret;
+ fail:
+ bf_set_nan(r);
+ return BF_ST_MEM_ERROR;
+}
+
+static int __bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
+ bf_flags_t flags)
+{
+ return bf_add_internal(r, a, b, prec, flags, 0);
+}
+
+static int __bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
+ bf_flags_t flags)
+{
+ return bf_add_internal(r, a, b, prec, flags, 1);
+}
+
+limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2,
+ limb_t n, limb_t carry)
+{
+ slimb_t i;
+ limb_t k, a, v, k1;
+
+ k = carry;
+ for(i=0;i<n;i++) {
+ v = op1[i];
+ a = v + op2[i];
+ k1 = a < v;
+ a = a + k;
+ k = (a < k) | k1;
+ res[i] = a;
+ }
+ return k;
+}
+
+limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n)
+{
+ size_t i;
+ limb_t k, a;
+
+ k=b;
+ for(i=0;i<n;i++) {
+ if (k == 0)
+ break;
+ a = tab[i] + k;
+ k = (a < k);
+ tab[i] = a;
+ }
+ return k;
+}
+
+limb_t mp_sub(limb_t *res, const limb_t *op1, const limb_t *op2,
+ mp_size_t n, limb_t carry)
+{
+ int i;
+ limb_t k, a, v, k1;
+
+ k = carry;
+ for(i=0;i<n;i++) {
+ v = op1[i];
+ a = v - op2[i];
+ k1 = a > v;
+ v = a - k;
+ k = (v > a) | k1;
+ res[i] = v;
+ }
+ return k;
+}
+
+/* compute 0 - op2 */
+static limb_t mp_neg(limb_t *res, const limb_t *op2, mp_size_t n, limb_t carry)
+{
+ int i;
+ limb_t k, a, v, k1;
+
+ k = carry;
+ for(i=0;i<n;i++) {
+ v = 0;
+ a = v - op2[i];
+ k1 = a > v;
+ v = a - k;
+ k = (v > a) | k1;
+ res[i] = v;
+ }
+ return k;
+}
+
+limb_t mp_sub_ui(limb_t *tab, limb_t b, mp_size_t n)
+{
+ mp_size_t i;
+ limb_t k, a, v;
+
+ k=b;
+ for(i=0;i<n;i++) {
+ v = tab[i];
+ a = v - k;
+ k = a > v;
+ tab[i] = a;
+ if (k == 0)
+ break;
+ }
+ return k;
+}
+
+/* r = (a + high*B^n) >> shift. Return the remainder r (0 <= r < 2^shift).
+ 1 <= shift <= LIMB_BITS - 1 */
+static limb_t mp_shr(limb_t *tab_r, const limb_t *tab, mp_size_t n,
+ int shift, limb_t high)
+{
+ mp_size_t i;
+ limb_t l, a;
+
+ assert(shift >= 1 && shift < LIMB_BITS);
+ l = high;
+ for(i = n - 1; i >= 0; i--) {
+ a = tab[i];
+ tab_r[i] = (a >> shift) | (l << (LIMB_BITS - shift));
+ l = a;
+ }
+ return l & (((limb_t)1 << shift) - 1);
+}
+
+/* tabr[] = taba[] * b + l. Return the high carry */
+static limb_t mp_mul1(limb_t *tabr, const limb_t *taba, limb_t n,
+ limb_t b, limb_t l)
+{
+ limb_t i;
+ dlimb_t t;
+
+ for(i = 0; i < n; i++) {
+ t = (dlimb_t)taba[i] * (dlimb_t)b + l;
+ tabr[i] = t;
+ l = t >> LIMB_BITS;
+ }
+ return l;
+}
+
+/* tabr[] += taba[] * b, return the high word. */
+static limb_t mp_add_mul1(limb_t *tabr, const limb_t *taba, limb_t n,
+ limb_t b)
+{
+ limb_t i, l;
+ dlimb_t t;
+
+ l = 0;
+ for(i = 0; i < n; i++) {
+ t = (dlimb_t)taba[i] * (dlimb_t)b + l + tabr[i];
+ tabr[i] = t;
+ l = t >> LIMB_BITS;
+ }
+ return l;
+}
+
+/* size of the result : op1_size + op2_size. */
+static void mp_mul_basecase(limb_t *result,
+ const limb_t *op1, limb_t op1_size,
+ const limb_t *op2, limb_t op2_size)
+{
+ limb_t i, r;
+
+ result[op1_size] = mp_mul1(result, op1, op1_size, op2[0], 0);
+ for(i=1;i<op2_size;i++) {
+ r = mp_add_mul1(result + i, op1, op1_size, op2[i]);
+ result[i + op1_size] = r;
+ }
+}
+
+/* return 0 if OK, -1 if memory error */
+/* XXX: change API so that result can be allocated */
+int mp_mul(bf_context_t *s, limb_t *result,
+ const limb_t *op1, limb_t op1_size,
+ const limb_t *op2, limb_t op2_size)
+{
+#ifdef USE_FFT_MUL
+ if (unlikely(bf_min(op1_size, op2_size) >= FFT_MUL_THRESHOLD)) {
+ bf_t r_s, *r = &r_s;
+ r->tab = result;
+ /* XXX: optimize memory usage in API */
+ if (fft_mul(s, r, (limb_t *)op1, op1_size,
+ (limb_t *)op2, op2_size, FFT_MUL_R_NORESIZE))
+ return -1;
+ } else
+#endif
+ {
+ mp_mul_basecase(result, op1, op1_size, op2, op2_size);
+ }
+ return 0;
+}
+
+/* tabr[] -= taba[] * b. Return the value to substract to the high
+ word. */
+static limb_t mp_sub_mul1(limb_t *tabr, const limb_t *taba, limb_t n,
+ limb_t b)
+{
+ limb_t i, l;
+ dlimb_t t;
+
+ l = 0;
+ for(i = 0; i < n; i++) {
+ t = tabr[i] - (dlimb_t)taba[i] * (dlimb_t)b - l;
+ tabr[i] = t;
+ l = -(t >> LIMB_BITS);
+ }
+ return l;
+}
+
+/* WARNING: d must be >= 2^(LIMB_BITS-1) */
+static inline limb_t udiv1norm_init(limb_t d)
+{
+ limb_t a0, a1;
+ a1 = -d - 1;
+ a0 = -1;
+ return (((dlimb_t)a1 << LIMB_BITS) | a0) / d;
+}
+
+/* return the quotient and the remainder in '*pr'of 'a1*2^LIMB_BITS+a0
+ / d' with 0 <= a1 < d. */
+static inline limb_t udiv1norm(limb_t *pr, limb_t a1, limb_t a0,
+ limb_t d, limb_t d_inv)
+{
+ limb_t n1m, n_adj, q, r, ah;
+ dlimb_t a;
+ n1m = ((slimb_t)a0 >> (LIMB_BITS - 1));
+ n_adj = a0 + (n1m & d);
+ a = (dlimb_t)d_inv * (a1 - n1m) + n_adj;
+ q = (a >> LIMB_BITS) + a1;
+ /* compute a - q * r and update q so that the remainder is\
+ between 0 and d - 1 */
+ a = ((dlimb_t)a1 << LIMB_BITS) | a0;
+ a = a - (dlimb_t)q * d - d;
+ ah = a >> LIMB_BITS;
+ q += 1 + ah;
+ r = (limb_t)a + (ah & d);
+ *pr = r;
+ return q;
+}
+
+/* b must be >= 1 << (LIMB_BITS - 1) */
+static limb_t mp_div1norm(limb_t *tabr, const limb_t *taba, limb_t n,
+ limb_t b, limb_t r)
+{
+ slimb_t i;
+
+ if (n >= UDIV1NORM_THRESHOLD) {
+ limb_t b_inv;
+ b_inv = udiv1norm_init(b);
+ for(i = n - 1; i >= 0; i--) {
+ tabr[i] = udiv1norm(&r, r, taba[i], b, b_inv);
+ }
+ } else {
+ dlimb_t a1;
+ for(i = n - 1; i >= 0; i--) {
+ a1 = ((dlimb_t)r << LIMB_BITS) | taba[i];
+ tabr[i] = a1 / b;
+ r = a1 % b;
+ }
+ }
+ return r;
+}
+
+static int mp_divnorm_large(bf_context_t *s,
+ limb_t *tabq, limb_t *taba, limb_t na,
+ const limb_t *tabb, limb_t nb);
+
+/* base case division: divides taba[0..na-1] by tabb[0..nb-1]. tabb[nb
+ - 1] must be >= 1 << (LIMB_BITS - 1). na - nb must be >= 0. 'taba'
+ is modified and contains the remainder (nb limbs). tabq[0..na-nb]
+ contains the quotient with tabq[na - nb] <= 1. */
+static int mp_divnorm(bf_context_t *s, limb_t *tabq, limb_t *taba, limb_t na,
+ const limb_t *tabb, limb_t nb)
+{
+ limb_t r, a, c, q, v, b1, b1_inv, n, dummy_r;
+ slimb_t i, j;
+
+ b1 = tabb[nb - 1];
+ if (nb == 1) {
+ taba[0] = mp_div1norm(tabq, taba, na, b1, 0);
+ return 0;
+ }
+ n = na - nb;
+ if (bf_min(n, nb) >= DIVNORM_LARGE_THRESHOLD) {
+ return mp_divnorm_large(s, tabq, taba, na, tabb, nb);
+ }
+
+ if (n >= UDIV1NORM_THRESHOLD)
+ b1_inv = udiv1norm_init(b1);
+ else
+ b1_inv = 0;
+
+ /* first iteration: the quotient is only 0 or 1 */
+ q = 1;
+ for(j = nb - 1; j >= 0; j--) {
+ if (taba[n + j] != tabb[j]) {
+ if (taba[n + j] < tabb[j])
+ q = 0;
+ break;
+ }
+ }
+ tabq[n] = q;
+ if (q) {
+ mp_sub(taba + n, taba + n, tabb, nb, 0);
+ }
+
+ for(i = n - 1; i >= 0; i--) {
+ if (unlikely(taba[i + nb] >= b1)) {
+ q = -1;
+ } else if (b1_inv) {
+ q = udiv1norm(&dummy_r, taba[i + nb], taba[i + nb - 1], b1, b1_inv);
+ } else {
+ dlimb_t al;
+ al = ((dlimb_t)taba[i + nb] << LIMB_BITS) | taba[i + nb - 1];
+ q = al / b1;
+ r = al % b1;
+ }
+ r = mp_sub_mul1(taba + i, tabb, nb, q);
+
+ v = taba[i + nb];
+ a = v - r;
+ c = (a > v);
+ taba[i + nb] = a;
+
+ if (c != 0) {
+ /* negative result */
+ for(;;) {
+ q--;
+ c = mp_add(taba + i, taba + i, tabb, nb, 0);
+ /* propagate carry and test if positive result */
+ if (c != 0) {
+ if (++taba[i + nb] == 0) {
+ break;
+ }
+ }
+ }
+ }
+ tabq[i] = q;
+ }
+ return 0;
+}
+
+/* compute r=B^(2*n)/a such as a*r < B^(2*n) < a*r + 2 with n >= 1. 'a'
+ has n limbs with a[n-1] >= B/2 and 'r' has n+1 limbs with r[n] = 1.
+
+ See Modern Computer Arithmetic by Richard P. Brent and Paul
+ Zimmermann, algorithm 3.5 */
+int mp_recip(bf_context_t *s, limb_t *tabr, const limb_t *taba, limb_t n)
+{
+ mp_size_t l, h, k, i;
+ limb_t *tabxh, *tabt, c, *tabu;
+
+ if (n <= 2) {
+ /* return ceil(B^(2*n)/a) - 1 */
+ /* XXX: could avoid allocation */
+ tabu = bf_malloc(s, sizeof(limb_t) * (2 * n + 1));
+ tabt = bf_malloc(s, sizeof(limb_t) * (n + 2));
+ if (!tabt || !tabu)
+ goto fail;
+ for(i = 0; i < 2 * n; i++)
+ tabu[i] = 0;
+ tabu[2 * n] = 1;
+ if (mp_divnorm(s, tabt, tabu, 2 * n + 1, taba, n))
+ goto fail;
+ for(i = 0; i < n + 1; i++)
+ tabr[i] = tabt[i];
+ if (mp_scan_nz(tabu, n) == 0) {
+ /* only happens for a=B^n/2 */
+ mp_sub_ui(tabr, 1, n + 1);
+ }
+ } else {
+ l = (n - 1) / 2;
+ h = n - l;
+ /* n=2p -> l=p-1, h = p + 1, k = p + 3
+ n=2p+1-> l=p, h = p + 1; k = p + 2
+ */
+ tabt = bf_malloc(s, sizeof(limb_t) * (n + h + 1));
+ tabu = bf_malloc(s, sizeof(limb_t) * (n + 2 * h - l + 2));
+ if (!tabt || !tabu)
+ goto fail;
+ tabxh = tabr + l;
+ if (mp_recip(s, tabxh, taba + l, h))
+ goto fail;
+ if (mp_mul(s, tabt, taba, n, tabxh, h + 1)) /* n + h + 1 limbs */
+ goto fail;
+ while (tabt[n + h] != 0) {
+ mp_sub_ui(tabxh, 1, h + 1);
+ c = mp_sub(tabt, tabt, taba, n, 0);
+ mp_sub_ui(tabt + n, c, h + 1);
+ }
+ /* T = B^(n+h) - T */
+ mp_neg(tabt, tabt, n + h + 1, 0);
+ tabt[n + h]++;
+ if (mp_mul(s, tabu, tabt + l, n + h + 1 - l, tabxh, h + 1))
+ goto fail;
+ /* n + 2*h - l + 2 limbs */
+ k = 2 * h - l;
+ for(i = 0; i < l; i++)
+ tabr[i] = tabu[i + k];
+ mp_add(tabr + l, tabr + l, tabu + 2 * h, h, 0);
+ }
+ bf_free(s, tabt);
+ bf_free(s, tabu);
+ return 0;
+ fail:
+ bf_free(s, tabt);
+ bf_free(s, tabu);
+ return -1;
+}
+
+/* return -1, 0 or 1 */
+static int mp_cmp(const limb_t *taba, const limb_t *tabb, mp_size_t n)
+{
+ mp_size_t i;
+ for(i = n - 1; i >= 0; i--) {
+ if (taba[i] != tabb[i]) {
+ if (taba[i] < tabb[i])
+ return -1;
+ else
+ return 1;
+ }
+ }
+ return 0;
+}
+
+//#define DEBUG_DIVNORM_LARGE
+//#define DEBUG_DIVNORM_LARGE2
+
+/* subquadratic divnorm */
+static int mp_divnorm_large(bf_context_t *s,
+ limb_t *tabq, limb_t *taba, limb_t na,
+ const limb_t *tabb, limb_t nb)
+{
+ limb_t *tabb_inv, nq, *tabt, i, n;
+ nq = na - nb;
+#ifdef DEBUG_DIVNORM_LARGE
+ printf("na=%d nb=%d nq=%d\n", (int)na, (int)nb, (int)nq);
+ mp_print_str("a", taba, na);
+ mp_print_str("b", tabb, nb);
+#endif
+ assert(nq >= 1);
+ n = nq;
+ if (nq < nb)
+ n++;
+ tabb_inv = bf_malloc(s, sizeof(limb_t) * (n + 1));
+ tabt = bf_malloc(s, sizeof(limb_t) * 2 * (n + 1));
+ if (!tabb_inv || !tabt)
+ goto fail;
+
+ if (n >= nb) {
+ for(i = 0; i < n - nb; i++)
+ tabt[i] = 0;
+ for(i = 0; i < nb; i++)
+ tabt[i + n - nb] = tabb[i];
+ } else {
+ /* truncate B: need to increment it so that the approximate
+ inverse is smaller that the exact inverse */
+ for(i = 0; i < n; i++)
+ tabt[i] = tabb[i + nb - n];
+ if (mp_add_ui(tabt, 1, n)) {
+ /* tabt = B^n : tabb_inv = B^n */
+ memset(tabb_inv, 0, n * sizeof(limb_t));
+ tabb_inv[n] = 1;
+ goto recip_done;
+ }
+ }
+ if (mp_recip(s, tabb_inv, tabt, n))
+ goto fail;
+ recip_done:
+ /* Q=A*B^-1 */
+ if (mp_mul(s, tabt, tabb_inv, n + 1, taba + na - (n + 1), n + 1))
+ goto fail;
+
+ for(i = 0; i < nq + 1; i++)
+ tabq[i] = tabt[i + 2 * (n + 1) - (nq + 1)];
+#ifdef DEBUG_DIVNORM_LARGE
+ mp_print_str("q", tabq, nq + 1);
+#endif
+
+ bf_free(s, tabt);
+ bf_free(s, tabb_inv);
+ tabb_inv = NULL;
+
+ /* R=A-B*Q */
+ tabt = bf_malloc(s, sizeof(limb_t) * (na + 1));
+ if (!tabt)
+ goto fail;
+ if (mp_mul(s, tabt, tabq, nq + 1, tabb, nb))
+ goto fail;
+ /* we add one more limb for the result */
+ mp_sub(taba, taba, tabt, nb + 1, 0);
+ bf_free(s, tabt);
+ /* the approximated quotient is smaller than than the exact one,
+ hence we may have to increment it */
+#ifdef DEBUG_DIVNORM_LARGE2
+ int cnt = 0;
+ static int cnt_max;
+#endif
+ for(;;) {
+ if (taba[nb] == 0 && mp_cmp(taba, tabb, nb) < 0)
+ break;
+ taba[nb] -= mp_sub(taba, taba, tabb, nb, 0);
+ mp_add_ui(tabq, 1, nq + 1);
+#ifdef DEBUG_DIVNORM_LARGE2
+ cnt++;
+#endif
+ }
+#ifdef DEBUG_DIVNORM_LARGE2
+ if (cnt > cnt_max) {
+ cnt_max = cnt;
+ printf("\ncnt=%d nq=%d nb=%d\n", cnt_max, (int)nq, (int)nb);
+ }
+#endif
+ return 0;
+ fail:
+ bf_free(s, tabb_inv);
+ bf_free(s, tabt);
+ return -1;
+}
+
+int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
+ bf_flags_t flags)
+{
+ int ret, r_sign;
+
+ if (a->len < b->len) {
+ const bf_t *tmp = a;
+ a = b;
+ b = tmp;
+ }
+ r_sign = a->sign ^ b->sign;
+ /* here b->len <= a->len */
+ if (b->len == 0) {
+ if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
+ bf_set_nan(r);
+ ret = 0;
+ } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_INF) {
+ if ((a->expn == BF_EXP_INF && b->expn == BF_EXP_ZERO) ||
+ (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_INF)) {
+ bf_set_nan(r);
+ ret = BF_ST_INVALID_OP;
+ } else {
+ bf_set_inf(r, r_sign);
+ ret = 0;
+ }
+ } else {
+ bf_set_zero(r, r_sign);
+ ret = 0;
+ }
+ } else {
+ bf_t tmp, *r1 = NULL;
+ limb_t a_len, b_len, precl;
+ limb_t *a_tab, *b_tab;
+
+ a_len = a->len;
+ b_len = b->len;
+
+ if ((flags & BF_RND_MASK) == BF_RNDF) {
+ /* faithful rounding does not require using the full inputs */
+ precl = (prec + 2 + LIMB_BITS - 1) / LIMB_BITS;
+ a_len = bf_min(a_len, precl);
+ b_len = bf_min(b_len, precl);
+ }
+ a_tab = a->tab + a->len - a_len;
+ b_tab = b->tab + b->len - b_len;
+
+#ifdef USE_FFT_MUL
+ if (b_len >= FFT_MUL_THRESHOLD) {
+ int mul_flags = 0;
+ if (r == a)
+ mul_flags |= FFT_MUL_R_OVERLAP_A;
+ if (r == b)
+ mul_flags |= FFT_MUL_R_OVERLAP_B;
+ if (fft_mul(r->ctx, r, a_tab, a_len, b_tab, b_len, mul_flags))
+ goto fail;
+ } else
+#endif
+ {
+ if (r == a || r == b) {
+ bf_init(r->ctx, &tmp);
+ r1 = r;
+ r = &tmp;
+ }
+ if (bf_resize(r, a_len + b_len)) {
+#ifdef USE_FFT_MUL
+ fail:
+#endif
+ bf_set_nan(r);
+ ret = BF_ST_MEM_ERROR;
+ goto done;
+ }
+ mp_mul_basecase(r->tab, a_tab, a_len, b_tab, b_len);
+ }
+ r->sign = r_sign;
+ r->expn = a->expn + b->expn;
+ ret = bf_normalize_and_round(r, prec, flags);
+ done:
+ if (r == &tmp)
+ bf_move(r1, &tmp);
+ }
+ return ret;
+}
+
+/* multiply 'r' by 2^e */
+int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags)
+{
+ slimb_t e_max;
+ if (r->len == 0)
+ return 0;
+ e_max = ((limb_t)1 << BF_EXT_EXP_BITS_MAX) - 1;
+ e = bf_max(e, -e_max);
+ e = bf_min(e, e_max);
+ r->expn += e;
+ return __bf_round(r, prec, flags, r->len, 0);
+}
+
+/* Return e such as a=m*2^e with m odd integer. return 0 if a is zero,
+ Infinite or Nan. */
+slimb_t bf_get_exp_min(const bf_t *a)
+{
+ slimb_t i;
+ limb_t v;
+ int k;
+
+ for(i = 0; i < a->len; i++) {
+ v = a->tab[i];
+ if (v != 0) {
+ k = ctz(v);
+ return a->expn - (a->len - i) * LIMB_BITS + k;
+ }
+ }
+ return 0;
+}
+
+/* a and b must be finite numbers with a >= 0 and b > 0. 'q' is the
+ integer defined as floor(a/b) and r = a - q * b. */
+static void bf_tdivremu(bf_t *q, bf_t *r,
+ const bf_t *a, const bf_t *b)
+{
+ if (bf_cmpu(a, b) < 0) {
+ bf_set_ui(q, 0);
+ bf_set(r, a);
+ } else {
+ bf_div(q, a, b, bf_max(a->expn - b->expn + 1, 2), BF_RNDZ);
+ bf_rint(q, BF_RNDZ);
+ bf_mul(r, q, b, BF_PREC_INF, BF_RNDZ);
+ bf_sub(r, a, r, BF_PREC_INF, BF_RNDZ);
+ }
+}
+
+static int __bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
+ bf_flags_t flags)
+{
+ bf_context_t *s = r->ctx;
+ int ret, r_sign;
+ limb_t n, nb, precl;
+
+ r_sign = a->sign ^ b->sign;
+ if (a->expn >= BF_EXP_INF || b->expn >= BF_EXP_INF) {
+ if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
+ bf_set_nan(r);
+ return 0;
+ } else if (a->expn == BF_EXP_INF && b->expn == BF_EXP_INF) {
+ bf_set_nan(r);
+ return BF_ST_INVALID_OP;
+ } else if (a->expn == BF_EXP_INF) {
+ bf_set_inf(r, r_sign);
+ return 0;
+ } else {
+ bf_set_zero(r, r_sign);
+ return 0;
+ }
+ } else if (a->expn == BF_EXP_ZERO) {
+ if (b->expn == BF_EXP_ZERO) {
+ bf_set_nan(r);
+ return BF_ST_INVALID_OP;
+ } else {
+ bf_set_zero(r, r_sign);
+ return 0;
+ }
+ } else if (b->expn == BF_EXP_ZERO) {
+ bf_set_inf(r, r_sign);
+ return BF_ST_DIVIDE_ZERO;
+ }
+
+ /* number of limbs of the quotient (2 extra bits for rounding) */
+ precl = (prec + 2 + LIMB_BITS - 1) / LIMB_BITS;
+ nb = b->len;
+ n = bf_max(a->len, precl);
+
+ {
+ limb_t *taba, na;
+ slimb_t d;
+
+ na = n + nb;
+ taba = bf_malloc(s, (na + 1) * sizeof(limb_t));
+ if (!taba)
+ goto fail;
+ d = na - a->len;
+ memset(taba, 0, d * sizeof(limb_t));
+ memcpy(taba + d, a->tab, a->len * sizeof(limb_t));
+ if (bf_resize(r, n + 1))
+ goto fail1;
+ if (mp_divnorm(s, r->tab, taba, na, b->tab, nb)) {
+ fail1:
+ bf_free(s, taba);
+ goto fail;
+ }
+ /* see if non zero remainder */
+ if (mp_scan_nz(taba, nb))
+ r->tab[0] |= 1;
+ bf_free(r->ctx, taba);
+ r->expn = a->expn - b->expn + LIMB_BITS;
+ r->sign = r_sign;
+ ret = bf_normalize_and_round(r, prec, flags);
+ }
+ return ret;
+ fail:
+ bf_set_nan(r);
+ return BF_ST_MEM_ERROR;
+}
+
+/* division and remainder.
+
+ rnd_mode is the rounding mode for the quotient. The additional
+ rounding mode BF_RND_EUCLIDIAN is supported.
+
+ 'q' is an integer. 'r' is rounded with prec and flags (prec can be
+ BF_PREC_INF).
+*/
+int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b,
+ limb_t prec, bf_flags_t flags, int rnd_mode)
+{
+ bf_t a1_s, *a1 = &a1_s;
+ bf_t b1_s, *b1 = &b1_s;
+ int q_sign, ret;
+ BOOL is_ceil, is_rndn;
+
+ assert(q != a && q != b);
+ assert(r != a && r != b);
+ assert(q != r);
+
+ if (a->len == 0 || b->len == 0) {
+ bf_set_zero(q, 0);
+ if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
+ bf_set_nan(r);
+ return 0;
+ } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_ZERO) {
+ bf_set_nan(r);
+ return BF_ST_INVALID_OP;
+ } else {
+ bf_set(r, a);
+ return bf_round(r, prec, flags);
+ }
+ }
+
+ q_sign = a->sign ^ b->sign;
+ is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);
+ switch(rnd_mode) {
+ default:
+ case BF_RNDZ:
+ case BF_RNDN:
+ case BF_RNDNA:
+ is_ceil = FALSE;
+ break;
+ case BF_RNDD:
+ is_ceil = q_sign;
+ break;
+ case BF_RNDU:
+ is_ceil = q_sign ^ 1;
+ break;
+ case BF_RNDA:
+ is_ceil = TRUE;
+ break;
+ case BF_DIVREM_EUCLIDIAN:
+ is_ceil = a->sign;
+ break;
+ }
+
+ a1->expn = a->expn;
+ a1->tab = a->tab;
+ a1->len = a->len;
+ a1->sign = 0;
+
+ b1->expn = b->expn;
+ b1->tab = b->tab;
+ b1->len = b->len;
+ b1->sign = 0;
+
+ /* XXX: could improve to avoid having a large 'q' */
+ bf_tdivremu(q, r, a1, b1);
+ if (bf_is_nan(q) || bf_is_nan(r))
+ goto fail;
+
+ if (r->len != 0) {
+ if (is_rndn) {
+ int res;
+ b1->expn--;
+ res = bf_cmpu(r, b1);
+ b1->expn++;
+ if (res > 0 ||
+ (res == 0 &&
+ (rnd_mode == BF_RNDNA ||
+ get_bit(q->tab, q->len, q->len * LIMB_BITS - q->expn)))) {
+ goto do_sub_r;
+ }
+ } else if (is_ceil) {
+ do_sub_r:
+ ret = bf_add_si(q, q, 1, BF_PREC_INF, BF_RNDZ);
+ ret |= bf_sub(r, r, b1, BF_PREC_INF, BF_RNDZ);
+ if (ret & BF_ST_MEM_ERROR)
+ goto fail;
+ }
+ }
+
+ r->sign ^= a->sign;
+ q->sign = q_sign;
+ return bf_round(r, prec, flags);
+ fail:
+ bf_set_nan(q);
+ bf_set_nan(r);
+ return BF_ST_MEM_ERROR;
+}
+
+int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
+ bf_flags_t flags, int rnd_mode)
+{
+ bf_t q_s, *q = &q_s;
+ int ret;
+
+ bf_init(r->ctx, q);
+ ret = bf_divrem(q, r, a, b, prec, flags, rnd_mode);
+ bf_delete(q);
+ return ret;
+}
+
+static inline int bf_get_limb(slimb_t *pres, const bf_t *a, int flags)
+{
+#if LIMB_BITS == 32
+ return bf_get_int32(pres, a, flags);
+#else
+ return bf_get_int64(pres, a, flags);
+#endif
+}
+
+int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
+ bf_flags_t flags, int rnd_mode)
+{
+ bf_t q_s, *q = &q_s;
+ int ret;
+
+ bf_init(r->ctx, q);
+ ret = bf_divrem(q, r, a, b, prec, flags, rnd_mode);
+ bf_get_limb(pq, q, BF_GET_INT_MOD);
+ bf_delete(q);
+ return ret;
+}
+
+static __maybe_unused inline limb_t mul_mod(limb_t a, limb_t b, limb_t m)
+{
+ dlimb_t t;
+ t = (dlimb_t)a * (dlimb_t)b;
+ return t % m;
+}
+
+#if defined(USE_MUL_CHECK)
+static limb_t mp_mod1(const limb_t *tab, limb_t n, limb_t m, limb_t r)
+{
+ slimb_t i;
+ dlimb_t t;
+
+ for(i = n - 1; i >= 0; i--) {
+ t = ((dlimb_t)r << LIMB_BITS) | tab[i];
+ r = t % m;
+ }
+ return r;
+}
+#endif
+
+static const uint16_t sqrt_table[192] = {
+128,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,144,145,146,147,148,149,150,150,151,152,153,154,155,155,156,157,158,159,160,160,161,162,163,163,164,165,166,167,167,168,169,170,170,171,172,173,173,174,175,176,176,177,178,178,179,180,181,181,182,183,183,184,185,185,186,187,187,188,189,189,190,191,192,192,193,193,194,195,195,196,197,197,198,199,199,200,201,201,202,203,203,204,204,205,206,206,207,208,208,209,209,210,211,211,212,212,213,214,214,215,215,216,217,217,218,218,219,219,220,221,221,222,222,223,224,224,225,225,226,226,227,227,228,229,229,230,230,231,231,232,232,233,234,234,235,235,236,236,237,237,238,238,239,240,240,241,241,242,242,243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,251,252,252,253,253,254,254,255,
+};
+
+/* a >= 2^(LIMB_BITS - 2). Return (s, r) with s=floor(sqrt(a)) and
+ r=a-s^2. 0 <= r <= 2 * s */
+static limb_t mp_sqrtrem1(limb_t *pr, limb_t a)
+{
+ limb_t s1, r1, s, r, q, u, num;
+
+ /* use a table for the 16 -> 8 bit sqrt */
+ s1 = sqrt_table[(a >> (LIMB_BITS - 8)) - 64];
+ r1 = (a >> (LIMB_BITS - 16)) - s1 * s1;
+ if (r1 > 2 * s1) {
+ r1 -= 2 * s1 + 1;
+ s1++;
+ }
+
+ /* one iteration to get a 32 -> 16 bit sqrt */
+ num = (r1 << 8) | ((a >> (LIMB_BITS - 32 + 8)) & 0xff);
+ q = num / (2 * s1); /* q <= 2^8 */
+ u = num % (2 * s1);
+ s = (s1 << 8) + q;
+ r = (u << 8) | ((a >> (LIMB_BITS - 32)) & 0xff);
+ r -= q * q;
+ if ((slimb_t)r < 0) {
+ s--;
+ r += 2 * s + 1;
+ }
+
+#if LIMB_BITS == 64
+ s1 = s;
+ r1 = r;
+ /* one more iteration for 64 -> 32 bit sqrt */
+ num = (r1 << 16) | ((a >> (LIMB_BITS - 64 + 16)) & 0xffff);
+ q = num / (2 * s1); /* q <= 2^16 */
+ u = num % (2 * s1);
+ s = (s1 << 16) + q;
+ r = (u << 16) | ((a >> (LIMB_BITS - 64)) & 0xffff);
+ r -= q * q;
+ if ((slimb_t)r < 0) {
+ s--;
+ r += 2 * s + 1;
+ }
+#endif
+ *pr = r;
+ return s;
+}
+
+/* return floor(sqrt(a)) */
+limb_t bf_isqrt(limb_t a)
+{
+ limb_t s, r;
+ int k;
+
+ if (a == 0)
+ return 0;
+ k = clz(a) & ~1;
+ s = mp_sqrtrem1(&r, a << k);
+ s >>= (k >> 1);
+ return s;
+}
+
+static limb_t mp_sqrtrem2(limb_t *tabs, limb_t *taba)
+{
+ limb_t s1, r1, s, q, u, a0, a1;
+ dlimb_t r, num;
+ int l;
+
+ a0 = taba[0];
+ a1 = taba[1];
+ s1 = mp_sqrtrem1(&r1, a1);
+ l = LIMB_BITS / 2;
+ num = ((dlimb_t)r1 << l) | (a0 >> l);
+ q = num / (2 * s1);
+ u = num % (2 * s1);
+ s = (s1 << l) + q;
+ r = ((dlimb_t)u << l) | (a0 & (((limb_t)1 << l) - 1));
+ if (unlikely((q >> l) != 0))
+ r -= (dlimb_t)1 << LIMB_BITS; /* special case when q=2^l */
+ else
+ r -= q * q;
+ if ((slimb_t)(r >> LIMB_BITS) < 0) {
+ s--;
+ r += 2 * (dlimb_t)s + 1;
+ }
+ tabs[0] = s;
+ taba[0] = r;
+ return r >> LIMB_BITS;
+}
+
+//#define DEBUG_SQRTREM
+
+/* tmp_buf must contain (n / 2 + 1 limbs). *prh contains the highest
+ limb of the remainder. */
+static int mp_sqrtrem_rec(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n,
+ limb_t *tmp_buf, limb_t *prh)
+{
+ limb_t l, h, rh, ql, qh, c, i;
+
+ if (n == 1) {
+ *prh = mp_sqrtrem2(tabs, taba);
+ return 0;
+ }
+#ifdef DEBUG_SQRTREM
+ mp_print_str("a", taba, 2 * n);
+#endif
+ l = n / 2;
+ h = n - l;
+ if (mp_sqrtrem_rec(s, tabs + l, taba + 2 * l, h, tmp_buf, &qh))
+ return -1;
+#ifdef DEBUG_SQRTREM
+ mp_print_str("s1", tabs + l, h);
+ mp_print_str_h("r1", taba + 2 * l, h, qh);
+ mp_print_str_h("r2", taba + l, n, qh);
+#endif
+
+ /* the remainder is in taba + 2 * l. Its high bit is in qh */
+ if (qh) {
+ mp_sub(taba + 2 * l, taba + 2 * l, tabs + l, h, 0);
+ }
+ /* instead of dividing by 2*s, divide by s (which is normalized)
+ and update q and r */
+ if (mp_divnorm(s, tmp_buf, taba + l, n, tabs + l, h))
+ return -1;
+ qh += tmp_buf[l];
+ for(i = 0; i < l; i++)
+ tabs[i] = tmp_buf[i];
+ ql = mp_shr(tabs, tabs, l, 1, qh & 1);
+ qh = qh >> 1; /* 0 or 1 */
+ if (ql)
+ rh = mp_add(taba + l, taba + l, tabs + l, h, 0);
+ else
+ rh = 0;
+#ifdef DEBUG_SQRTREM
+ mp_print_str_h("q", tabs, l, qh);
+ mp_print_str_h("u", taba + l, h, rh);
+#endif
+
+ mp_add_ui(tabs + l, qh, h);
+#ifdef DEBUG_SQRTREM
+ mp_print_str_h("s2", tabs, n, sh);
+#endif
+
+ /* q = qh, tabs[l - 1 ... 0], r = taba[n - 1 ... l] */
+ /* subtract q^2. if qh = 1 then q = B^l, so we can take shortcuts */
+ if (qh) {
+ c = qh;
+ } else {
+ if (mp_mul(s, taba + n, tabs, l, tabs, l))
+ return -1;
+ c = mp_sub(taba, taba, taba + n, 2 * l, 0);
+ }
+ rh -= mp_sub_ui(taba + 2 * l, c, n - 2 * l);
+ if ((slimb_t)rh < 0) {
+ mp_sub_ui(tabs, 1, n);
+ rh += mp_add_mul1(taba, tabs, n, 2);
+ rh += mp_add_ui(taba, 1, n);
+ }
+ *prh = rh;
+ return 0;
+}
+
+/* 'taba' has 2*n limbs with n >= 1 and taba[2*n-1] >= 2 ^ (LIMB_BITS
+ - 2). Return (s, r) with s=floor(sqrt(a)) and r=a-s^2. 0 <= r <= 2
+ * s. tabs has n limbs. r is returned in the lower n limbs of
+ taba. Its r[n] is the returned value of the function. */
+/* Algorithm from the article "Karatsuba Square Root" by Paul Zimmermann and
+ inspirated from its GMP implementation */
+int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n)
+{
+ limb_t tmp_buf1[8];
+ limb_t *tmp_buf;
+ mp_size_t n2;
+ int ret;
+ n2 = n / 2 + 1;
+ if (n2 <= countof(tmp_buf1)) {
+ tmp_buf = tmp_buf1;
+ } else {
+ tmp_buf = bf_malloc(s, sizeof(limb_t) * n2);
+ if (!tmp_buf)
+ return -1;
+ }
+ ret = mp_sqrtrem_rec(s, tabs, taba, n, tmp_buf, taba + n);
+ if (tmp_buf != tmp_buf1)
+ bf_free(s, tmp_buf);
+ return ret;
+}
+
+/* Integer square root with remainder. 'a' must be an integer. r =
+ floor(sqrt(a)) and rem = a - r^2. BF_ST_INEXACT is set if the result
+ is inexact. 'rem' can be NULL if the remainder is not needed. */
+int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a)
+{
+ int ret;
+
+ if (a->len == 0) {
+ if (a->expn == BF_EXP_NAN) {
+ bf_set_nan(r);
+ } else if (a->expn == BF_EXP_INF && a->sign) {
+ goto invalid_op;
+ } else {
+ bf_set(r, a);
+ }
+ if (rem1)
+ bf_set_ui(rem1, 0);
+ ret = 0;
+ } else if (a->sign) {
+ invalid_op:
+ bf_set_nan(r);
+ if (rem1)
+ bf_set_ui(rem1, 0);
+ ret = BF_ST_INVALID_OP;
+ } else {
+ bf_t rem_s, *rem;
+
+ bf_sqrt(r, a, (a->expn + 1) / 2, BF_RNDZ);
+ bf_rint(r, BF_RNDZ);
+ /* see if the result is exact by computing the remainder */
+ if (rem1) {
+ rem = rem1;
+ } else {
+ rem = &rem_s;
+ bf_init(r->ctx, rem);
+ }
+ /* XXX: could avoid recomputing the remainder */
+ bf_mul(rem, r, r, BF_PREC_INF, BF_RNDZ);
+ bf_neg(rem);
+ bf_add(rem, rem, a, BF_PREC_INF, BF_RNDZ);
+ if (bf_is_nan(rem)) {
+ ret = BF_ST_MEM_ERROR;
+ goto done;
+ }
+ if (rem->len != 0) {
+ ret = BF_ST_INEXACT;
+ } else {
+ ret = 0;
+ }
+ done:
+ if (!rem1)
+ bf_delete(rem);
+ }
+ return ret;
+}
+
+int bf_sqrt(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
+{
+ bf_context_t *s = a->ctx;
+ int ret;
+
+ assert(r != a);
+
+ if (a->len == 0) {
+ if (a->expn == BF_EXP_NAN) {
+ bf_set_nan(r);
+ } else if (a->expn == BF_EXP_INF && a->sign) {
+ goto invalid_op;
+ } else {
+ bf_set(r, a);
+ }
+ ret = 0;
+ } else if (a->sign) {
+ invalid_op:
+ bf_set_nan(r);
+ ret = BF_ST_INVALID_OP;
+ } else {
+ limb_t *a1;
+ slimb_t n, n1;
+ limb_t res;
+
+ /* convert the mantissa to an integer with at least 2 *
+ prec + 4 bits */
+ n = (2 * (prec + 2) + 2 * LIMB_BITS - 1) / (2 * LIMB_BITS);
+ if (bf_resize(r, n))
+ goto fail;
+ a1 = bf_malloc(s, sizeof(limb_t) * 2 * n);
+ if (!a1)
+ goto fail;
+ n1 = bf_min(2 * n, a->len);
+ memset(a1, 0, (2 * n - n1) * sizeof(limb_t));
+ memcpy(a1 + 2 * n - n1, a->tab + a->len - n1, n1 * sizeof(limb_t));
+ if (a->expn & 1) {
+ res = mp_shr(a1, a1, 2 * n, 1, 0);
+ } else {
+ res = 0;
+ }
+ if (mp_sqrtrem(s, r->tab, a1, n)) {
+ bf_free(s, a1);
+ goto fail;
+ }
+ if (!res) {
+ res = mp_scan_nz(a1, n + 1);
+ }
+ bf_free(s, a1);
+ if (!res) {
+ res = mp_scan_nz(a->tab, a->len - n1);
+ }
+ if (res != 0)
+ r->tab[0] |= 1;
+ r->sign = 0;
+ r->expn = (a->expn + 1) >> 1;
+ ret = bf_round(r, prec, flags);
+ }
+ return ret;
+ fail:
+ bf_set_nan(r);
+ return BF_ST_MEM_ERROR;
+}
+
+static no_inline int bf_op2(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
+ bf_flags_t flags, bf_op2_func_t *func)
+{
+ bf_t tmp;
+ int ret;
+
+ if (r == a || r == b) {
+ bf_init(r->ctx, &tmp);
+ ret = func(&tmp, a, b, prec, flags);
+ bf_move(r, &tmp);
+ } else {
+ ret = func(r, a, b, prec, flags);
+ }
+ return ret;
+}
+
+int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
+ bf_flags_t flags)
+{
+ return bf_op2(r, a, b, prec, flags, __bf_add);
+}
+
+int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
+ bf_flags_t flags)
+{
+ return bf_op2(r, a, b, prec, flags, __bf_sub);
+}
+
+int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
+ bf_flags_t flags)
+{
+ return bf_op2(r, a, b, prec, flags, __bf_div);
+}
+
+int bf_mul_ui(bf_t *r, const bf_t *a, uint64_t b1, limb_t prec,
+ bf_flags_t flags)
+{
+ bf_t b;
+ int ret;
+ bf_init(r->ctx, &b);
+ ret = bf_set_ui(&b, b1);
+ ret |= bf_mul(r, a, &b, prec, flags);
+ bf_delete(&b);
+ return ret;
+}
+
+int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec,
+ bf_flags_t flags)
+{
+ bf_t b;
+ int ret;
+ bf_init(r->ctx, &b);
+ ret = bf_set_si(&b, b1);
+ ret |= bf_mul(r, a, &b, prec, flags);
+ bf_delete(&b);
+ return ret;
+}
+
+int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec,
+ bf_flags_t flags)
+{
+ bf_t b;
+ int ret;
+
+ bf_init(r->ctx, &b);
+ ret = bf_set_si(&b, b1);
+ ret |= bf_add(r, a, &b, prec, flags);
+ bf_delete(&b);
+ return ret;
+}
+
+static int bf_pow_ui(bf_t *r, const bf_t *a, limb_t b, limb_t prec,
+ bf_flags_t flags)
+{
+ int ret, n_bits, i;
+
+ assert(r != a);
+ if (b == 0)
+ return bf_set_ui(r, 1);
+ ret = bf_set(r, a);
+ n_bits = LIMB_BITS - clz(b);
+ for(i = n_bits - 2; i >= 0; i--) {
+ ret |= bf_mul(r, r, r, prec, flags);
+ if ((b >> i) & 1)
+ ret |= bf_mul(r, r, a, prec, flags);
+ }
+ return ret;
+}
+
+static int bf_pow_ui_ui(bf_t *r, limb_t a1, limb_t b,
+ limb_t prec, bf_flags_t flags)
+{
+ bf_t a;
+ int ret;
+
+#ifdef USE_BF_DEC
+ if (a1 == 10 && b <= LIMB_DIGITS) {
+ /* use precomputed powers. We do not round at this point
+ because we expect the caller to do it */
+ ret = bf_set_ui(r, mp_pow_dec[b]);
+ } else
+#endif
+ {
+ bf_init(r->ctx, &a);
+ ret = bf_set_ui(&a, a1);
+ ret |= bf_pow_ui(r, &a, b, prec, flags);
+ bf_delete(&a);
+ }
+ return ret;
+}
+
+/* convert to integer (infinite precision) */
+int bf_rint(bf_t *r, int rnd_mode)
+{
+ return bf_round(r, 0, rnd_mode | BF_FLAG_RADPNT_PREC);
+}
+
+/* logical operations */
+#define BF_LOGIC_OR 0
+#define BF_LOGIC_XOR 1
+#define BF_LOGIC_AND 2
+
+static inline limb_t bf_logic_op1(limb_t a, limb_t b, int op)
+{
+ switch(op) {
+ case BF_LOGIC_OR:
+ return a | b;
+ case BF_LOGIC_XOR:
+ return a ^ b;
+ default:
+ case BF_LOGIC_AND:
+ return a & b;
+ }
+}
+
+static int bf_logic_op(bf_t *r, const bf_t *a1, const bf_t *b1, int op)
+{
+ bf_t b1_s, a1_s, *a, *b;
+ limb_t a_sign, b_sign, r_sign;
+ slimb_t l, i, a_bit_offset, b_bit_offset;
+ limb_t v1, v2, v1_mask, v2_mask, r_mask;
+ int ret;
+
+ assert(r != a1 && r != b1);
+
+ if (a1->expn <= 0)
+ a_sign = 0; /* minus zero is considered as positive */
+ else
+ a_sign = a1->sign;
+
+ if (b1->expn <= 0)
+ b_sign = 0; /* minus zero is considered as positive */
+ else
+ b_sign = b1->sign;
+
+ if (a_sign) {
+ a = &a1_s;
+ bf_init(r->ctx, a);
+ if (bf_add_si(a, a1, 1, BF_PREC_INF, BF_RNDZ)) {
+ b = NULL;
+ goto fail;
+ }
+ } else {
+ a = (bf_t *)a1;
+ }
+
+ if (b_sign) {
+ b = &b1_s;
+ bf_init(r->ctx, b);
+ if (bf_add_si(b, b1, 1, BF_PREC_INF, BF_RNDZ))
+ goto fail;
+ } else {
+ b = (bf_t *)b1;
+ }
+
+ r_sign = bf_logic_op1(a_sign, b_sign, op);
+ if (op == BF_LOGIC_AND && r_sign == 0) {
+ /* no need to compute extra zeros for and */
+ if (a_sign == 0 && b_sign == 0)
+ l = bf_min(a->expn, b->expn);
+ else if (a_sign == 0)
+ l = a->expn;
+ else
+ l = b->expn;
+ } else {
+ l = bf_max(a->expn, b->expn);
+ }
+ /* Note: a or b can be zero */
+ l = (bf_max(l, 1) + LIMB_BITS - 1) / LIMB_BITS;
+ if (bf_resize(r, l))
+ goto fail;
+ a_bit_offset = a->len * LIMB_BITS - a->expn;
+ b_bit_offset = b->len * LIMB_BITS - b->expn;
+ v1_mask = -a_sign;
+ v2_mask = -b_sign;
+ r_mask = -r_sign;
+ for(i = 0; i < l; i++) {
+ v1 = get_bits(a->tab, a->len, a_bit_offset + i * LIMB_BITS) ^ v1_mask;
+ v2 = get_bits(b->tab, b->len, b_bit_offset + i * LIMB_BITS) ^ v2_mask;
+ r->tab[i] = bf_logic_op1(v1, v2, op) ^ r_mask;
+ }
+ r->expn = l * LIMB_BITS;
+ r->sign = r_sign;
+ bf_normalize_and_round(r, BF_PREC_INF, BF_RNDZ); /* cannot fail */
+ if (r_sign) {
+ if (bf_add_si(r, r, -1, BF_PREC_INF, BF_RNDZ))
+ goto fail;
+ }
+ ret = 0;
+ done:
+ if (a == &a1_s)
+ bf_delete(a);
+ if (b == &b1_s)
+ bf_delete(b);
+ return ret;
+ fail:
+ bf_set_nan(r);
+ ret = BF_ST_MEM_ERROR;
+ goto done;
+}
+
+/* 'a' and 'b' must be integers. Return 0 or BF_ST_MEM_ERROR. */
+int bf_logic_or(bf_t *r, const bf_t *a, const bf_t *b)
+{
+ return bf_logic_op(r, a, b, BF_LOGIC_OR);
+}
+
+/* 'a' and 'b' must be integers. Return 0 or BF_ST_MEM_ERROR. */
+int bf_logic_xor(bf_t *r, const bf_t *a, const bf_t *b)
+{
+ return bf_logic_op(r, a, b, BF_LOGIC_XOR);
+}
+
+/* 'a' and 'b' must be integers. Return 0 or BF_ST_MEM_ERROR. */
+int bf_logic_and(bf_t *r, const bf_t *a, const bf_t *b)
+{
+ return bf_logic_op(r, a, b, BF_LOGIC_AND);
+}
+
+/* conversion between fixed size types */
+
+typedef union {
+ double d;
+ uint64_t u;
+} Float64Union;
+
+int bf_get_float64(const bf_t *a, double *pres, bf_rnd_t rnd_mode)
+{
+ Float64Union u;
+ int e, ret;
+ uint64_t m;
+
+ ret = 0;
+ if (a->expn == BF_EXP_NAN) {
+ u.u = 0x7ff8000000000000; /* quiet nan */
+ } else {
+ bf_t b_s, *b = &b_s;
+
+ bf_init(a->ctx, b);
+ bf_set(b, a);
+ if (bf_is_finite(b)) {
+ ret = bf_round(b, 53, rnd_mode | BF_FLAG_SUBNORMAL | bf_set_exp_bits(11));
+ }
+ if (b->expn == BF_EXP_INF) {
+ e = (1 << 11) - 1;
+ m = 0;
+ } else if (b->expn == BF_EXP_ZERO) {
+ e = 0;
+ m = 0;
+ } else {
+ e = b->expn + 1023 - 1;
+#if LIMB_BITS == 32
+ if (b->len == 2) {
+ m = ((uint64_t)b->tab[1] << 32) | b->tab[0];
+ } else {
+ m = ((uint64_t)b->tab[0] << 32);
+ }
+#else
+ m = b->tab[0];
+#endif
+ if (e <= 0) {
+ /* subnormal */
+ m = m >> (12 - e);
+ e = 0;
+ } else {
+ m = (m << 1) >> 12;
+ }
+ }
+ u.u = m | ((uint64_t)e << 52) | ((uint64_t)b->sign << 63);
+ bf_delete(b);
+ }
+ *pres = u.d;
+ return ret;
+}
+
+int bf_set_float64(bf_t *a, double d)
+{
+ Float64Union u;
+ uint64_t m;
+ int shift, e, sgn;
+
+ u.d = d;
+ sgn = u.u >> 63;
+ e = (u.u >> 52) & ((1 << 11) - 1);
+ m = u.u & (((uint64_t)1 << 52) - 1);
+ if (e == ((1 << 11) - 1)) {
+ if (m != 0) {
+ bf_set_nan(a);
+ } else {
+ bf_set_inf(a, sgn);
+ }
+ } else if (e == 0) {
+ if (m == 0) {
+ bf_set_zero(a, sgn);
+ } else {
+ /* subnormal number */
+ m <<= 12;
+ shift = clz64(m);
+ m <<= shift;
+ e = -shift;
+ goto norm;
+ }
+ } else {
+ m = (m << 11) | ((uint64_t)1 << 63);
+ norm:
+ a->expn = e - 1023 + 1;
+#if LIMB_BITS == 32
+ if (bf_resize(a, 2))
+ goto fail;
+ a->tab[0] = m;
+ a->tab[1] = m >> 32;
+#else
+ if (bf_resize(a, 1))
+ goto fail;
+ a->tab[0] = m;
+#endif
+ a->sign = sgn;
+ }
+ return 0;
+fail:
+ bf_set_nan(a);
+ return BF_ST_MEM_ERROR;
+}
+
+/* The rounding mode is always BF_RNDZ. Return BF_ST_INVALID_OP if there
+ is an overflow and 0 otherwise. */
+int bf_get_int32(int *pres, const bf_t *a, int flags)
+{
+ uint32_t v;
+ int ret;
+ if (a->expn >= BF_EXP_INF) {
+ ret = BF_ST_INVALID_OP;
+ if (flags & BF_GET_INT_MOD) {
+ v = 0;
+ } else if (a->expn == BF_EXP_INF) {
+ v = (uint32_t)INT32_MAX + a->sign;
+ } else {
+ v = INT32_MAX;
+ }
+ } else if (a->expn <= 0) {
+ v = 0;
+ ret = 0;
+ } else if (a->expn <= 31) {
+ v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);
+ if (a->sign)
+ v = -v;
+ ret = 0;
+ } else if (!(flags & BF_GET_INT_MOD)) {
+ ret = BF_ST_INVALID_OP;
+ if (a->sign) {
+ v = (uint32_t)INT32_MAX + 1;
+ if (a->expn == 32 &&
+ (a->tab[a->len - 1] >> (LIMB_BITS - 32)) == v) {
+ ret = 0;
+ }
+ } else {
+ v = INT32_MAX;
+ }
+ } else {
+ v = get_bits(a->tab, a->len, a->len * LIMB_BITS - a->expn);
+ if (a->sign)
+ v = -v;
+ ret = 0;
+ }
+ *pres = v;
+ return ret;
+}
+
+/* The rounding mode is always BF_RNDZ. Return BF_ST_INVALID_OP if there
+ is an overflow and 0 otherwise. */
+int bf_get_int64(int64_t *pres, const bf_t *a, int flags)
+{
+ uint64_t v;
+ int ret;
+ if (a->expn >= BF_EXP_INF) {
+ ret = BF_ST_INVALID_OP;
+ if (flags & BF_GET_INT_MOD) {
+ v = 0;
+ } else if (a->expn == BF_EXP_INF) {
+ v = (uint64_t)INT64_MAX + a->sign;
+ } else {
+ v = INT64_MAX;
+ }
+ } else if (a->expn <= 0) {
+ v = 0;
+ ret = 0;
+ } else if (a->expn <= 63) {
+#if LIMB_BITS == 32
+ if (a->expn <= 32)
+ v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);
+ else
+ v = (((uint64_t)a->tab[a->len - 1] << 32) |
+ get_limbz(a, a->len - 2)) >> (64 - a->expn);
+#else
+ v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);
+#endif
+ if (a->sign)
+ v = -v;
+ ret = 0;
+ } else if (!(flags & BF_GET_INT_MOD)) {
+ ret = BF_ST_INVALID_OP;
+ if (a->sign) {
+ uint64_t v1;
+ v = (uint64_t)INT64_MAX + 1;
+ if (a->expn == 64) {
+ v1 = a->tab[a->len - 1];
+#if LIMB_BITS == 32
+ v1 = (v1 << 32) | get_limbz(a, a->len - 2);
+#endif
+ if (v1 == v)
+ ret = 0;
+ }
+ } else {
+ v = INT64_MAX;
+ }
+ } else {
+ slimb_t bit_pos = a->len * LIMB_BITS - a->expn;
+ v = get_bits(a->tab, a->len, bit_pos);
+#if LIMB_BITS == 32
+ v |= (uint64_t)get_bits(a->tab, a->len, bit_pos + 32) << 32;
+#endif
+ if (a->sign)
+ v = -v;
+ ret = 0;
+ }
+ *pres = v;
+ return ret;
+}
+
+/* The rounding mode is always BF_RNDZ. Return BF_ST_INVALID_OP if there
+ is an overflow and 0 otherwise. */
+int bf_get_uint64(uint64_t *pres, const bf_t *a)
+{
+ uint64_t v;
+ int ret;
+ if (a->expn == BF_EXP_NAN) {
+ goto overflow;
+ } else if (a->expn <= 0) {
+ v = 0;
+ ret = 0;
+ } else if (a->sign) {
+ v = 0;
+ ret = BF_ST_INVALID_OP;
+ } else if (a->expn <= 64) {
+#if LIMB_BITS == 32
+ if (a->expn <= 32)
+ v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);
+ else
+ v = (((uint64_t)a->tab[a->len - 1] << 32) |
+ get_limbz(a, a->len - 2)) >> (64 - a->expn);
+#else
+ v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);
+#endif
+ ret = 0;
+ } else {
+ overflow:
+ v = UINT64_MAX;
+ ret = BF_ST_INVALID_OP;
+ }
+ *pres = v;
+ return ret;
+}
+
+/* base conversion from radix */
+
+static const uint8_t digits_per_limb_table[BF_RADIX_MAX - 1] = {
+#if LIMB_BITS == 32
+32,20,16,13,12,11,10,10, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+#else
+64,40,32,27,24,22,21,20,19,18,17,17,16,16,16,15,15,15,14,14,14,14,13,13,13,13,13,13,13,12,12,12,12,12,12,
+#endif
+};
+
+static limb_t get_limb_radix(int radix)
+{
+ int i, k;
+ limb_t radixl;
+
+ k = digits_per_limb_table[radix - 2];
+ radixl = radix;
+ for(i = 1; i < k; i++)
+ radixl *= radix;
+ return radixl;
+}
+
+/* return != 0 if error */
+static int bf_integer_from_radix_rec(bf_t *r, const limb_t *tab,
+ limb_t n, int level, limb_t n0,
+ limb_t radix, bf_t *pow_tab)
+{
+ int ret;
+ if (n == 1) {
+ ret = bf_set_ui(r, tab[0]);
+ } else {
+ bf_t T_s, *T = &T_s, *B;
+ limb_t n1, n2;
+
+ n2 = (((n0 * 2) >> (level + 1)) + 1) / 2;
+ n1 = n - n2;
+ // printf("level=%d n0=%ld n1=%ld n2=%ld\n", level, n0, n1, n2);
+ B = &pow_tab[level];
+ if (B->len == 0) {
+ ret = bf_pow_ui_ui(B, radix, n2, BF_PREC_INF, BF_RNDZ);
+ if (ret)
+ return ret;
+ }
+ ret = bf_integer_from_radix_rec(r, tab + n2, n1, level + 1, n0,
+ radix, pow_tab);
+ if (ret)
+ return ret;
+ ret = bf_mul(r, r, B, BF_PREC_INF, BF_RNDZ);
+ if (ret)
+ return ret;
+ bf_init(r->ctx, T);
+ ret = bf_integer_from_radix_rec(T, tab, n2, level + 1, n0,
+ radix, pow_tab);
+ if (!ret)
+ ret = bf_add(r, r, T, BF_PREC_INF, BF_RNDZ);
+ bf_delete(T);
+ }
+ return ret;
+ // bf_print_str(" r=", r);
+}
+
+/* return 0 if OK != 0 if memory error */
+static int bf_integer_from_radix(bf_t *r, const limb_t *tab,
+ limb_t n, limb_t radix)
+{
+ bf_context_t *s = r->ctx;
+ int pow_tab_len, i, ret;
+ limb_t radixl;
+ bf_t *pow_tab;
+
+ radixl = get_limb_radix(radix);
+ pow_tab_len = ceil_log2(n) + 2; /* XXX: check */
+ pow_tab = bf_malloc(s, sizeof(pow_tab[0]) * pow_tab_len);
+ if (!pow_tab)
+ return -1;
+ for(i = 0; i < pow_tab_len; i++)
+ bf_init(r->ctx, &pow_tab[i]);
+ ret = bf_integer_from_radix_rec(r, tab, n, 0, n, radixl, pow_tab);
+ for(i = 0; i < pow_tab_len; i++) {
+ bf_delete(&pow_tab[i]);
+ }
+ bf_free(s, pow_tab);
+ return ret;
+}
+
+/* compute and round T * radix^expn. */
+int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix,
+ slimb_t expn, limb_t prec, bf_flags_t flags)
+{
+ int ret, expn_sign, overflow;
+ slimb_t e, extra_bits, prec1, ziv_extra_bits;
+ bf_t B_s, *B = &B_s;
+
+ if (T->len == 0) {
+ return bf_set(r, T);
+ } else if (expn == 0) {
+ ret = bf_set(r, T);
+ ret |= bf_round(r, prec, flags);
+ return ret;
+ }
+
+ e = expn;
+ expn_sign = 0;
+ if (e < 0) {
+ e = -e;
+ expn_sign = 1;
+ }
+ bf_init(r->ctx, B);
+ if (prec == BF_PREC_INF) {
+ /* infinite precision: only used if the result is known to be exact */
+ ret = bf_pow_ui_ui(B, radix, e, BF_PREC_INF, BF_RNDN);
+ if (expn_sign) {
+ ret |= bf_div(r, T, B, T->len * LIMB_BITS, BF_RNDN);
+ } else {
+ ret |= bf_mul(r, T, B, BF_PREC_INF, BF_RNDN);
+ }
+ } else {
+ ziv_extra_bits = 16;
+ for(;;) {
+ prec1 = prec + ziv_extra_bits;
+ /* XXX: correct overflow/underflow handling */
+ /* XXX: rigorous error analysis needed */
+ extra_bits = ceil_log2(e) * 2 + 1;
+ ret = bf_pow_ui_ui(B, radix, e, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP);
+ overflow = !bf_is_finite(B);
+ /* XXX: if bf_pow_ui_ui returns an exact result, can stop
+ after the next operation */
+ if (expn_sign)
+ ret |= bf_div(r, T, B, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP);
+ else
+ ret |= bf_mul(r, T, B, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP);
+ if (ret & BF_ST_MEM_ERROR)
+ break;
+ if ((ret & BF_ST_INEXACT) &&
+ !bf_can_round(r, prec, flags & BF_RND_MASK, prec1) &&
+ !overflow) {
+ /* and more precision and retry */
+ ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2);
+ } else {
+ /* XXX: need to use __bf_round() to pass the inexact
+ flag for the subnormal case */
+ ret = bf_round(r, prec, flags) | (ret & BF_ST_INEXACT);
+ break;
+ }
+ }
+ }
+ bf_delete(B);
+ return ret;
+}
+
+static inline int to_digit(int c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'A' && c <= 'Z')
+ return c - 'A' + 10;
+ else if (c >= 'a' && c <= 'z')
+ return c - 'a' + 10;
+ else
+ return 36;
+}
+
+/* add a limb at 'pos' and decrement pos. new space is created if
+ needed. Return 0 if OK, -1 if memory error */
+static int bf_add_limb(bf_t *a, slimb_t *ppos, limb_t v)
+{
+ slimb_t pos;
+ pos = *ppos;
+ if (unlikely(pos < 0)) {
+ limb_t new_size, d, *new_tab;
+ new_size = bf_max(a->len + 1, a->len * 3 / 2);
+ new_tab = bf_realloc(a->ctx, a->tab, sizeof(limb_t) * new_size);
+ if (!new_tab)
+ return -1;
+ a->tab = new_tab;
+ d = new_size - a->len;
+ memmove(a->tab + d, a->tab, a->len * sizeof(limb_t));
+ a->len = new_size;
+ pos += d;
+ }
+ a->tab[pos--] = v;
+ *ppos = pos;
+ return 0;
+}
+
+static int bf_tolower(int c)
+{
+ if (c >= 'A' && c <= 'Z')
+ c = c - 'A' + 'a';
+ return c;
+}
+
+static int strcasestart(const char *str, const char *val, const char **ptr)
+{
+ const char *p, *q;
+ p = str;
+ q = val;
+ while (*q != '\0') {
+ if (bf_tolower(*p) != *q)
+ return 0;
+ p++;
+ q++;
+ }
+ if (ptr)
+ *ptr = p;
+ return 1;
+}
+
+static int bf_atof_internal(bf_t *r, slimb_t *pexponent,
+ const char *str, const char **pnext, int radix,
+ limb_t prec, bf_flags_t flags, BOOL is_dec)
+{
+ const char *p, *p_start;
+ int is_neg, radix_bits, exp_is_neg, ret, digits_per_limb, shift;
+ limb_t cur_limb;
+ slimb_t pos, expn, int_len, digit_count;
+ BOOL has_decpt, is_bin_exp;
+ bf_t a_s, *a;
+
+ *pexponent = 0;
+ p = str;
+ if (!(flags & BF_ATOF_NO_NAN_INF) && radix <= 16 &&
+ strcasestart(p, "nan", &p)) {
+ bf_set_nan(r);
+ ret = 0;
+ goto done;
+ }
+ is_neg = 0;
+
+ if (p[0] == '+') {
+ p++;
+ p_start = p;
+ } else if (p[0] == '-') {
+ is_neg = 1;
+ p++;
+ p_start = p;
+ } else {
+ p_start = p;
+ }
+ if (p[0] == '0') {
+ if ((p[1] == 'x' || p[1] == 'X') &&
+ (radix == 0 || radix == 16) &&
+ !(flags & BF_ATOF_NO_HEX)) {
+ radix = 16;
+ p += 2;
+ } else if ((p[1] == 'o' || p[1] == 'O') &&
+ radix == 0 && (flags & BF_ATOF_BIN_OCT)) {
+ p += 2;
+ radix = 8;
+ } else if ((p[1] == 'b' || p[1] == 'B') &&
+ radix == 0 && (flags & BF_ATOF_BIN_OCT)) {
+ p += 2;
+ radix = 2;
+ } else {
+ goto no_prefix;
+ }
+ /* there must be a digit after the prefix */
+ if (to_digit((uint8_t)*p) >= radix) {
+ bf_set_nan(r);
+ ret = 0;
+ goto done;
+ }
+ no_prefix: ;
+ } else {
+ if (!(flags & BF_ATOF_NO_NAN_INF) && radix <= 16 &&
+ strcasestart(p, "inf", &p)) {
+ bf_set_inf(r, is_neg);
+ ret = 0;
+ goto done;
+ }
+ }
+
+ if (radix == 0)
+ radix = 10;
+ if (is_dec) {
+ assert(radix == 10);
+ radix_bits = 0;
+ a = r;
+ } else if ((radix & (radix - 1)) != 0) {
+ radix_bits = 0; /* base is not a power of two */
+ a = &a_s;
+ bf_init(r->ctx, a);
+ } else {
+ radix_bits = ceil_log2(radix);
+ a = r;
+ }
+
+ /* skip leading zeros */
+ /* XXX: could also skip zeros after the decimal point */
+ while (*p == '0')
+ p++;
+
+ if (radix_bits) {
+ shift = digits_per_limb = LIMB_BITS;
+ } else {
+ radix_bits = 0;
+ shift = digits_per_limb = digits_per_limb_table[radix - 2];
+ }
+ cur_limb = 0;
+ bf_resize(a, 1);
+ pos = 0;
+ has_decpt = FALSE;
+ int_len = digit_count = 0;
+ for(;;) {
+ limb_t c;
+ if (*p == '.' && (p > p_start || to_digit(p[1]) < radix)) {
+ if (has_decpt)
+ break;
+ has_decpt = TRUE;
+ int_len = digit_count;
+ p++;
+ }
+ c = to_digit(*p);
+ if (c >= radix)
+ break;
+ digit_count++;
+ p++;
+ if (radix_bits) {
+ shift -= radix_bits;
+ if (shift <= 0) {
+ cur_limb |= c >> (-shift);
+ if (bf_add_limb(a, &pos, cur_limb))
+ goto mem_error;
+ if (shift < 0)
+ cur_limb = c << (LIMB_BITS + shift);
+ else
+ cur_limb = 0;
+ shift += LIMB_BITS;
+ } else {
+ cur_limb |= c << shift;
+ }
+ } else {
+ cur_limb = cur_limb * radix + c;
+ shift--;
+ if (shift == 0) {
+ if (bf_add_limb(a, &pos, cur_limb))
+ goto mem_error;
+ shift = digits_per_limb;
+ cur_limb = 0;
+ }
+ }
+ }
+ if (!has_decpt)
+ int_len = digit_count;
+
+ /* add the last limb and pad with zeros */
+ if (shift != digits_per_limb) {
+ if (radix_bits == 0) {
+ while (shift != 0) {
+ cur_limb *= radix;
+ shift--;
+ }
+ }
+ if (bf_add_limb(a, &pos, cur_limb)) {
+ mem_error:
+ ret = BF_ST_MEM_ERROR;
+ if (!radix_bits)
+ bf_delete(a);
+ bf_set_nan(r);
+ goto done;
+ }
+ }
+
+ /* reset the next limbs to zero (we prefer to reallocate in the
+ renormalization) */
+ memset(a->tab, 0, (pos + 1) * sizeof(limb_t));
+
+ if (p == p_start) {
+ ret = 0;
+ if (!radix_bits)
+ bf_delete(a);
+ bf_set_nan(r);
+ goto done;
+ }
+
+ /* parse the exponent, if any */
+ expn = 0;
+ is_bin_exp = FALSE;
+ if (((radix == 10 && (*p == 'e' || *p == 'E')) ||
+ (radix != 10 && (*p == '@' ||
+ (radix_bits && (*p == 'p' || *p == 'P'))))) &&
+ p > p_start) {
+ is_bin_exp = (*p == 'p' || *p == 'P');
+ p++;
+ exp_is_neg = 0;
+ if (*p == '+') {
+ p++;
+ } else if (*p == '-') {
+ exp_is_neg = 1;
+ p++;
+ }
+ for(;;) {
+ int c;
+ c = to_digit(*p);
+ if (c >= 10)
+ break;
+ if (unlikely(expn > ((BF_RAW_EXP_MAX - 2 - 9) / 10))) {
+ /* exponent overflow */
+ if (exp_is_neg) {
+ bf_set_zero(r, is_neg);
+ ret = BF_ST_UNDERFLOW | BF_ST_INEXACT;
+ } else {
+ bf_set_inf(r, is_neg);
+ ret = BF_ST_OVERFLOW | BF_ST_INEXACT;
+ }
+ goto done;
+ }
+ p++;
+ expn = expn * 10 + c;
+ }
+ if (exp_is_neg)
+ expn = -expn;
+ }
+ if (is_dec) {
+ a->expn = expn + int_len;
+ a->sign = is_neg;
+ ret = bfdec_normalize_and_round((bfdec_t *)a, prec, flags);
+ } else if (radix_bits) {
+ /* XXX: may overflow */
+ if (!is_bin_exp)
+ expn *= radix_bits;
+ a->expn = expn + (int_len * radix_bits);
+ a->sign = is_neg;
+ ret = bf_normalize_and_round(a, prec, flags);
+ } else {
+ limb_t l;
+ pos++;
+ l = a->len - pos; /* number of limbs */
+ if (l == 0) {
+ bf_set_zero(r, is_neg);
+ ret = 0;
+ } else {
+ bf_t T_s, *T = &T_s;
+
+ expn -= l * digits_per_limb - int_len;
+ bf_init(r->ctx, T);
+ if (bf_integer_from_radix(T, a->tab + pos, l, radix)) {
+ bf_set_nan(r);
+ ret = BF_ST_MEM_ERROR;
+ } else {
+ T->sign = is_neg;
+ if (flags & BF_ATOF_EXPONENT) {
+ /* return the exponent */
+ *pexponent = expn;
+ ret = bf_set(r, T);
+ } else {
+ ret = bf_mul_pow_radix(r, T, radix, expn, prec, flags);
+ }
+ }
+ bf_delete(T);
+ }
+ bf_delete(a);
+ }
+ done:
+ if (pnext)
+ *pnext = p;
+ return ret;
+}
+
+/*
+ Return (status, n, exp). 'status' is the floating point status. 'n'
+ is the parsed number.
+
+ If (flags & BF_ATOF_EXPONENT) and if the radix is not a power of
+ two, the parsed number is equal to r *
+ (*pexponent)^radix. Otherwise *pexponent = 0.
+*/
+int bf_atof2(bf_t *r, slimb_t *pexponent,
+ const char *str, const char **pnext, int radix,
+ limb_t prec, bf_flags_t flags)
+{
+ return bf_atof_internal(r, pexponent, str, pnext, radix, prec, flags,
+ FALSE);
+}
+
+int bf_atof(bf_t *r, const char *str, const char **pnext, int radix,
+ limb_t prec, bf_flags_t flags)
+{
+ slimb_t dummy_exp;
+ return bf_atof_internal(r, &dummy_exp, str, pnext, radix, prec, flags, FALSE);
+}
+
+/* base conversion to radix */
+
+#if LIMB_BITS == 64
+#define RADIXL_10 UINT64_C(10000000000000000000)
+#else
+#define RADIXL_10 UINT64_C(1000000000)
+#endif
+
+static const uint32_t inv_log2_radix[BF_RADIX_MAX - 1][LIMB_BITS / 32 + 1] = {
+#if LIMB_BITS == 32
+{ 0x80000000, 0x00000000,},
+{ 0x50c24e60, 0xd4d4f4a7,},
+{ 0x40000000, 0x00000000,},
+{ 0x372068d2, 0x0a1ee5ca,},
+{ 0x3184648d, 0xb8153e7a,},
+{ 0x2d983275, 0x9d5369c4,},
+{ 0x2aaaaaaa, 0xaaaaaaab,},
+{ 0x28612730, 0x6a6a7a54,},
+{ 0x268826a1, 0x3ef3fde6,},
+{ 0x25001383, 0xbac8a744,},
+{ 0x23b46706, 0x82c0c709,},
+{ 0x229729f1, 0xb2c83ded,},
+{ 0x219e7ffd, 0xa5ad572b,},
+{ 0x20c33b88, 0xda7c29ab,},
+{ 0x20000000, 0x00000000,},
+{ 0x1f50b57e, 0xac5884b3,},
+{ 0x1eb22cc6, 0x8aa6e26f,},
+{ 0x1e21e118, 0x0c5daab2,},
+{ 0x1d9dcd21, 0x439834e4,},
+{ 0x1d244c78, 0x367a0d65,},
+{ 0x1cb40589, 0xac173e0c,},
+{ 0x1c4bd95b, 0xa8d72b0d,},
+{ 0x1bead768, 0x98f8ce4c,},
+{ 0x1b903469, 0x050f72e5,},
+{ 0x1b3b433f, 0x2eb06f15,},
+{ 0x1aeb6f75, 0x9c46fc38,},
+{ 0x1aa038eb, 0x0e3bfd17,},
+{ 0x1a593062, 0xb38d8c56,},
+{ 0x1a15f4c3, 0x2b95a2e6,},
+{ 0x19d630dc, 0xcc7ddef9,},
+{ 0x19999999, 0x9999999a,},
+{ 0x195fec80, 0x8a609431,},
+{ 0x1928ee7b, 0x0b4f22f9,},
+{ 0x18f46acf, 0x8c06e318,},
+{ 0x18c23246, 0xdc0a9f3d,},
+#else
+{ 0x80000000, 0x00000000, 0x00000000,},
+{ 0x50c24e60, 0xd4d4f4a7, 0x021f57bc,},
+{ 0x40000000, 0x00000000, 0x00000000,},
+{ 0x372068d2, 0x0a1ee5ca, 0x19ea911b,},
+{ 0x3184648d, 0xb8153e7a, 0x7fc2d2e1,},
+{ 0x2d983275, 0x9d5369c4, 0x4dec1661,},
+{ 0x2aaaaaaa, 0xaaaaaaaa, 0xaaaaaaab,},
+{ 0x28612730, 0x6a6a7a53, 0x810fabde,},
+{ 0x268826a1, 0x3ef3fde6, 0x23e2566b,},
+{ 0x25001383, 0xbac8a744, 0x385a3349,},
+{ 0x23b46706, 0x82c0c709, 0x3f891718,},
+{ 0x229729f1, 0xb2c83ded, 0x15fba800,},
+{ 0x219e7ffd, 0xa5ad572a, 0xe169744b,},
+{ 0x20c33b88, 0xda7c29aa, 0x9bddee52,},
+{ 0x20000000, 0x00000000, 0x00000000,},
+{ 0x1f50b57e, 0xac5884b3, 0x70e28eee,},
+{ 0x1eb22cc6, 0x8aa6e26f, 0x06d1a2a2,},
+{ 0x1e21e118, 0x0c5daab1, 0x81b4f4bf,},
+{ 0x1d9dcd21, 0x439834e3, 0x81667575,},
+{ 0x1d244c78, 0x367a0d64, 0xc8204d6d,},
+{ 0x1cb40589, 0xac173e0c, 0x3b7b16ba,},
+{ 0x1c4bd95b, 0xa8d72b0d, 0x5879f25a,},
+{ 0x1bead768, 0x98f8ce4c, 0x66cc2858,},
+{ 0x1b903469, 0x050f72e5, 0x0cf5488e,},
+{ 0x1b3b433f, 0x2eb06f14, 0x8c89719c,},
+{ 0x1aeb6f75, 0x9c46fc37, 0xab5fc7e9,},
+{ 0x1aa038eb, 0x0e3bfd17, 0x1bd62080,},
+{ 0x1a593062, 0xb38d8c56, 0x7998ab45,},
+{ 0x1a15f4c3, 0x2b95a2e6, 0x46aed6a0,},
+{ 0x19d630dc, 0xcc7ddef9, 0x5aadd61b,},
+{ 0x19999999, 0x99999999, 0x9999999a,},
+{ 0x195fec80, 0x8a609430, 0xe1106014,},
+{ 0x1928ee7b, 0x0b4f22f9, 0x5f69791d,},
+{ 0x18f46acf, 0x8c06e318, 0x4d2aeb2c,},
+{ 0x18c23246, 0xdc0a9f3d, 0x3fe16970,},
+#endif
+};
+
+static const limb_t log2_radix[BF_RADIX_MAX - 1] = {
+#if LIMB_BITS == 32
+0x20000000,
+0x32b80347,
+0x40000000,
+0x4a4d3c26,
+0x52b80347,
+0x59d5d9fd,
+0x60000000,
+0x6570068e,
+0x6a4d3c26,
+0x6eb3a9f0,
+0x72b80347,
+0x766a008e,
+0x79d5d9fd,
+0x7d053f6d,
+0x80000000,
+0x82cc7edf,
+0x8570068e,
+0x87ef05ae,
+0x8a4d3c26,
+0x8c8ddd45,
+0x8eb3a9f0,
+0x90c10501,
+0x92b80347,
+0x949a784c,
+0x966a008e,
+0x982809d6,
+0x99d5d9fd,
+0x9b74948f,
+0x9d053f6d,
+0x9e88c6b3,
+0xa0000000,
+0xa16bad37,
+0xa2cc7edf,
+0xa4231623,
+0xa570068e,
+#else
+0x2000000000000000,
+0x32b803473f7ad0f4,
+0x4000000000000000,
+0x4a4d3c25e68dc57f,
+0x52b803473f7ad0f4,
+0x59d5d9fd5010b366,
+0x6000000000000000,
+0x6570068e7ef5a1e8,
+0x6a4d3c25e68dc57f,
+0x6eb3a9f01975077f,
+0x72b803473f7ad0f4,
+0x766a008e4788cbcd,
+0x79d5d9fd5010b366,
+0x7d053f6d26089673,
+0x8000000000000000,
+0x82cc7edf592262d0,
+0x8570068e7ef5a1e8,
+0x87ef05ae409a0289,
+0x8a4d3c25e68dc57f,
+0x8c8ddd448f8b845a,
+0x8eb3a9f01975077f,
+0x90c10500d63aa659,
+0x92b803473f7ad0f4,
+0x949a784bcd1b8afe,
+0x966a008e4788cbcd,
+0x982809d5be7072dc,
+0x99d5d9fd5010b366,
+0x9b74948f5532da4b,
+0x9d053f6d26089673,
+0x9e88c6b3626a72aa,
+0xa000000000000000,
+0xa16bad3758efd873,
+0xa2cc7edf592262d0,
+0xa4231623369e78e6,
+0xa570068e7ef5a1e8,
+#endif
+};
+
+/* compute floor(a*b) or ceil(a*b) with b = log2(radix) or
+ b=1/log2(radix). For is_inv = 0, strict accuracy is not guaranteed
+ when radix is not a power of two. */
+slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv,
+ int is_ceil1)
+{
+ int is_neg;
+ limb_t a;
+ BOOL is_ceil;
+
+ is_ceil = is_ceil1;
+ a = a1;
+ if (a1 < 0) {
+ a = -a;
+ is_neg = 1;
+ } else {
+ is_neg = 0;
+ }
+ is_ceil ^= is_neg;
+ if ((radix & (radix - 1)) == 0) {
+ int radix_bits;
+ /* radix is a power of two */
+ radix_bits = ceil_log2(radix);
+ if (is_inv) {
+ if (is_ceil)
+ a += radix_bits - 1;
+ a = a / radix_bits;
+ } else {
+ a = a * radix_bits;
+ }
+ } else {
+ const uint32_t *tab;
+ limb_t b0, b1;
+ dlimb_t t;
+
+ if (is_inv) {
+ tab = inv_log2_radix[radix - 2];
+#if LIMB_BITS == 32
+ b1 = tab[0];
+ b0 = tab[1];
+#else
+ b1 = ((limb_t)tab[0] << 32) | tab[1];
+ b0 = (limb_t)tab[2] << 32;
+#endif
+ t = (dlimb_t)b0 * (dlimb_t)a;
+ t = (dlimb_t)b1 * (dlimb_t)a + (t >> LIMB_BITS);
+ a = t >> (LIMB_BITS - 1);
+ } else {
+ b0 = log2_radix[radix - 2];
+ t = (dlimb_t)b0 * (dlimb_t)a;
+ a = t >> (LIMB_BITS - 3);
+ }
+ /* a = floor(result) and 'result' cannot be an integer */
+ a += is_ceil;
+ }
+ if (is_neg)
+ a = -a;
+ return a;
+}
+
+/* 'n' is the number of output limbs */
+static int bf_integer_to_radix_rec(bf_t *pow_tab,
+ limb_t *out, const bf_t *a, limb_t n,
+ int level, limb_t n0, limb_t radixl,
+ unsigned int radixl_bits)
+{
+ limb_t n1, n2, q_prec;
+ int ret;
+
+ assert(n >= 1);
+ if (n == 1) {
+ out[0] = get_bits(a->tab, a->len, a->len * LIMB_BITS - a->expn);
+ } else if (n == 2) {
+ dlimb_t t;
+ slimb_t pos;
+ pos = a->len * LIMB_BITS - a->expn;
+ t = ((dlimb_t)get_bits(a->tab, a->len, pos + LIMB_BITS) << LIMB_BITS) |
+ get_bits(a->tab, a->len, pos);
+ if (likely(radixl == RADIXL_10)) {
+ /* use division by a constant when possible */
+ out[0] = t % RADIXL_10;
+ out[1] = t / RADIXL_10;
+ } else {
+ out[0] = t % radixl;
+ out[1] = t / radixl;
+ }
+ } else {
+ bf_t Q, R, *B, *B_inv;
+ int q_add;
+ bf_init(a->ctx, &Q);
+ bf_init(a->ctx, &R);
+ n2 = (((n0 * 2) >> (level + 1)) + 1) / 2;
+ n1 = n - n2;
+ B = &pow_tab[2 * level];
+ B_inv = &pow_tab[2 * level + 1];
+ ret = 0;
+ if (B->len == 0) {
+ /* compute BASE^n2 */
+ ret |= bf_pow_ui_ui(B, radixl, n2, BF_PREC_INF, BF_RNDZ);
+ /* we use enough bits for the maximum possible 'n1' value,
+ i.e. n2 + 1 */
+ ret |= bf_set_ui(&R, 1);
+ ret |= bf_div(B_inv, &R, B, (n2 + 1) * radixl_bits + 2, BF_RNDN);
+ }
+ // printf("%d: n1=% " PRId64 " n2=%" PRId64 "\n", level, n1, n2);
+ q_prec = n1 * radixl_bits;
+ ret |= bf_mul(&Q, a, B_inv, q_prec, BF_RNDN);
+ ret |= bf_rint(&Q, BF_RNDZ);
+
+ ret |= bf_mul(&R, &Q, B, BF_PREC_INF, BF_RNDZ);
+ ret |= bf_sub(&R, a, &R, BF_PREC_INF, BF_RNDZ);
+
+ if (ret & BF_ST_MEM_ERROR)
+ goto fail;
+ /* adjust if necessary */
+ q_add = 0;
+ while (R.sign && R.len != 0) {
+ if (bf_add(&R, &R, B, BF_PREC_INF, BF_RNDZ))
+ goto fail;
+ q_add--;
+ }
+ while (bf_cmpu(&R, B) >= 0) {
+ if (bf_sub(&R, &R, B, BF_PREC_INF, BF_RNDZ))
+ goto fail;
+ q_add++;
+ }
+ if (q_add != 0) {
+ if (bf_add_si(&Q, &Q, q_add, BF_PREC_INF, BF_RNDZ))
+ goto fail;
+ }
+ if (bf_integer_to_radix_rec(pow_tab, out + n2, &Q, n1, level + 1, n0,
+ radixl, radixl_bits))
+ goto fail;
+ if (bf_integer_to_radix_rec(pow_tab, out, &R, n2, level + 1, n0,
+ radixl, radixl_bits)) {
+ fail:
+ bf_delete(&Q);
+ bf_delete(&R);
+ return -1;
+ }
+ bf_delete(&Q);
+ bf_delete(&R);
+ }
+ return 0;
+}
+
+/* return 0 if OK != 0 if memory error */
+static int bf_integer_to_radix(bf_t *r, const bf_t *a, limb_t radixl)
+{
+ bf_context_t *s = r->ctx;
+ limb_t r_len;
+ bf_t *pow_tab;
+ int i, pow_tab_len, ret;
+
+ r_len = r->len;
+ pow_tab_len = (ceil_log2(r_len) + 2) * 2; /* XXX: check */
+ pow_tab = bf_malloc(s, sizeof(pow_tab[0]) * pow_tab_len);
+ if (!pow_tab)
+ return -1;
+ for(i = 0; i < pow_tab_len; i++)
+ bf_init(r->ctx, &pow_tab[i]);
+
+ ret = bf_integer_to_radix_rec(pow_tab, r->tab, a, r_len, 0, r_len, radixl,
+ ceil_log2(radixl));
+
+ for(i = 0; i < pow_tab_len; i++) {
+ bf_delete(&pow_tab[i]);
+ }
+ bf_free(s, pow_tab);
+ return ret;
+}
+
+/* a must be >= 0. 'P' is the wanted number of digits in radix
+ 'radix'. 'r' is the mantissa represented as an integer. *pE
+ contains the exponent. Return != 0 if memory error. */
+static int bf_convert_to_radix(bf_t *r, slimb_t *pE,
+ const bf_t *a, int radix,
+ limb_t P, bf_rnd_t rnd_mode,
+ BOOL is_fixed_exponent)
+{
+ slimb_t E, e, prec, extra_bits, ziv_extra_bits, prec0;
+ bf_t B_s, *B = &B_s;
+ int e_sign, ret, res;
+
+ if (a->len == 0) {
+ /* zero case */
+ *pE = 0;
+ return bf_set(r, a);
+ }
+
+ if (is_fixed_exponent) {
+ E = *pE;
+ } else {
+ /* compute the new exponent */
+ E = 1 + bf_mul_log2_radix(a->expn - 1, radix, TRUE, FALSE);
+ }
+ // bf_print_str("a", a);
+ // printf("E=%ld P=%ld radix=%d\n", E, P, radix);
+
+ for(;;) {
+ e = P - E;
+ e_sign = 0;
+ if (e < 0) {
+ e = -e;
+ e_sign = 1;
+ }
+ /* Note: precision for log2(radix) is not critical here */
+ prec0 = bf_mul_log2_radix(P, radix, FALSE, TRUE);
+ ziv_extra_bits = 16;
+ for(;;) {
+ prec = prec0 + ziv_extra_bits;
+ /* XXX: rigorous error analysis needed */
+ extra_bits = ceil_log2(e) * 2 + 1;
+ ret = bf_pow_ui_ui(r, radix, e, prec + extra_bits,
+ BF_RNDN | BF_FLAG_EXT_EXP);
+ if (!e_sign)
+ ret |= bf_mul(r, r, a, prec + extra_bits,
+ BF_RNDN | BF_FLAG_EXT_EXP);
+ else
+ ret |= bf_div(r, a, r, prec + extra_bits,
+ BF_RNDN | BF_FLAG_EXT_EXP);
+ if (ret & BF_ST_MEM_ERROR)
+ return BF_ST_MEM_ERROR;
+ /* if the result is not exact, check that it can be safely
+ rounded to an integer */
+ if ((ret & BF_ST_INEXACT) &&
+ !bf_can_round(r, r->expn, rnd_mode, prec)) {
+ /* and more precision and retry */
+ ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2);
+ continue;
+ } else {
+ ret = bf_rint(r, rnd_mode);
+ if (ret & BF_ST_MEM_ERROR)
+ return BF_ST_MEM_ERROR;
+ break;
+ }
+ }
+ if (is_fixed_exponent)
+ break;
+ /* check that the result is < B^P */
+ /* XXX: do a fast approximate test first ? */
+ bf_init(r->ctx, B);
+ ret = bf_pow_ui_ui(B, radix, P, BF_PREC_INF, BF_RNDZ);
+ if (ret) {
+ bf_delete(B);
+ return ret;
+ }
+ res = bf_cmpu(r, B);
+ bf_delete(B);
+ if (res < 0)
+ break;
+ /* try a larger exponent */
+ E++;
+ }
+ *pE = E;
+ return 0;
+}
+
+static void limb_to_a(char *buf, limb_t n, unsigned int radix, int len)
+{
+ int digit, i;
+
+ if (radix == 10) {
+ /* specific case with constant divisor */
+ for(i = len - 1; i >= 0; i--) {
+ digit = (limb_t)n % 10;
+ n = (limb_t)n / 10;
+ buf[i] = digit + '0';
+ }
+ } else {
+ for(i = len - 1; i >= 0; i--) {
+ digit = (limb_t)n % radix;
+ n = (limb_t)n / radix;
+ if (digit < 10)
+ digit += '0';
+ else
+ digit += 'a' - 10;
+ buf[i] = digit;
+ }
+ }
+}
+
+/* for power of 2 radixes */
+static void limb_to_a2(char *buf, limb_t n, unsigned int radix_bits, int len)
+{
+ int digit, i;
+ unsigned int mask;
+
+ mask = (1 << radix_bits) - 1;
+ for(i = len - 1; i >= 0; i--) {
+ digit = n & mask;
+ n >>= radix_bits;
+ if (digit < 10)
+ digit += '0';
+ else
+ digit += 'a' - 10;
+ buf[i] = digit;
+ }
+}
+
+/* 'a' must be an integer if the is_dec = FALSE or if the radix is not
+ a power of two. A dot is added before the 'dot_pos' digit. dot_pos
+ = n_digits does not display the dot. 0 <= dot_pos <=
+ n_digits. n_digits >= 1. */
+static void output_digits(DynBuf *s, const bf_t *a1, int radix, limb_t n_digits,
+ limb_t dot_pos, BOOL is_dec)
+{
+ limb_t i, v, l;
+ slimb_t pos, pos_incr;
+ int digits_per_limb, buf_pos, radix_bits, first_buf_pos;
+ char buf[65];
+ bf_t a_s, *a;
+
+ if (is_dec) {
+ digits_per_limb = LIMB_DIGITS;
+ a = (bf_t *)a1;
+ radix_bits = 0;
+ pos = a->len;
+ pos_incr = 1;
+ first_buf_pos = 0;
+ } else if ((radix & (radix - 1)) == 0) {
+ a = (bf_t *)a1;
+ radix_bits = ceil_log2(radix);
+ digits_per_limb = LIMB_BITS / radix_bits;
+ pos_incr = digits_per_limb * radix_bits;
+ /* digits are aligned relative to the radix point */
+ pos = a->len * LIMB_BITS + smod(-a->expn, radix_bits);
+ first_buf_pos = 0;
+ } else {
+ limb_t n, radixl;
+
+ digits_per_limb = digits_per_limb_table[radix - 2];
+ radixl = get_limb_radix(radix);
+ a = &a_s;
+ bf_init(a1->ctx, a);
+ n = (n_digits + digits_per_limb - 1) / digits_per_limb;
+ if (bf_resize(a, n)) {
+ dbuf_set_error(s);
+ goto done;
+ }
+ if (bf_integer_to_radix(a, a1, radixl)) {
+ dbuf_set_error(s);
+ goto done;
+ }
+ radix_bits = 0;
+ pos = n;
+ pos_incr = 1;
+ first_buf_pos = pos * digits_per_limb - n_digits;
+ }
+ buf_pos = digits_per_limb;
+ i = 0;
+ while (i < n_digits) {
+ if (buf_pos == digits_per_limb) {
+ pos -= pos_incr;
+ if (radix_bits == 0) {
+ v = get_limbz(a, pos);
+ limb_to_a(buf, v, radix, digits_per_limb);
+ } else {
+ v = get_bits(a->tab, a->len, pos);
+ limb_to_a2(buf, v, radix_bits, digits_per_limb);
+ }
+ buf_pos = first_buf_pos;
+ first_buf_pos = 0;
+ }
+ if (i < dot_pos) {
+ l = dot_pos;
+ } else {
+ if (i == dot_pos)
+ dbuf_putc(s, '.');
+ l = n_digits;
+ }
+ l = bf_min(digits_per_limb - buf_pos, l - i);
+ dbuf_put(s, (uint8_t *)(buf + buf_pos), l);
+ buf_pos += l;
+ i += l;
+ }
+ done:
+ if (a != a1)
+ bf_delete(a);
+}
+
+static void *bf_dbuf_realloc(void *opaque, void *ptr, size_t size)
+{
+ bf_context_t *s = opaque;
+ return bf_realloc(s, ptr, size);
+}
+
+/* return the length in bytes. A trailing '\0' is added */
+static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix,
+ limb_t prec, bf_flags_t flags, BOOL is_dec)
+{
+ bf_context_t *ctx = a2->ctx;
+ DynBuf s_s, *s = &s_s;
+ int radix_bits;
+
+ // bf_print_str("ftoa", a2);
+ // printf("radix=%d\n", radix);
+ dbuf_init2(s, ctx, bf_dbuf_realloc);
+ if (a2->expn == BF_EXP_NAN) {
+ dbuf_putstr(s, "NaN");
+ } else {
+ if (a2->sign)
+ dbuf_putc(s, '-');
+ if (a2->expn == BF_EXP_INF) {
+ if (flags & BF_FTOA_JS_QUIRKS)
+ dbuf_putstr(s, "Infinity");
+ else
+ dbuf_putstr(s, "Inf");
+ } else {
+ int fmt, ret;
+ slimb_t n_digits, n, i, n_max, n1;
+ bf_t a1_s, *a1 = &a1_s;
+
+ if ((radix & (radix - 1)) != 0)
+ radix_bits = 0;
+ else
+ radix_bits = ceil_log2(radix);
+
+ fmt = flags & BF_FTOA_FORMAT_MASK;
+ bf_init(ctx, a1);
+ if (fmt == BF_FTOA_FORMAT_FRAC) {
+ if (is_dec || radix_bits != 0) {
+ if (bf_set(a1, a2))
+ goto fail1;
+#ifdef USE_BF_DEC
+ if (is_dec) {
+ if (bfdec_round((bfdec_t *)a1, prec, (flags & BF_RND_MASK) | BF_FLAG_RADPNT_PREC) & BF_ST_MEM_ERROR)
+ goto fail1;
+ n = a1->expn;
+ } else
+#endif
+ {
+ if (bf_round(a1, prec * radix_bits, (flags & BF_RND_MASK) | BF_FLAG_RADPNT_PREC) & BF_ST_MEM_ERROR)
+ goto fail1;
+ n = ceil_div(a1->expn, radix_bits);
+ }
+ if (flags & BF_FTOA_ADD_PREFIX) {
+ if (radix == 16)
+ dbuf_putstr(s, "0x");
+ else if (radix == 8)
+ dbuf_putstr(s, "0o");
+ else if (radix == 2)
+ dbuf_putstr(s, "0b");
+ }
+ if (a1->expn == BF_EXP_ZERO) {
+ dbuf_putstr(s, "0");
+ if (prec > 0) {
+ dbuf_putstr(s, ".");
+ for(i = 0; i < prec; i++) {
+ dbuf_putc(s, '0');
+ }
+ }
+ } else {
+ n_digits = prec + n;
+ if (n <= 0) {
+ /* 0.x */
+ dbuf_putstr(s, "0.");
+ for(i = 0; i < -n; i++) {
+ dbuf_putc(s, '0');
+ }
+ if (n_digits > 0) {
+ output_digits(s, a1, radix, n_digits, n_digits, is_dec);
+ }
+ } else {
+ output_digits(s, a1, radix, n_digits, n, is_dec);
+ }
+ }
+ } else {
+ size_t pos, start;
+ bf_t a_s, *a = &a_s;
+
+ /* make a positive number */
+ a->tab = a2->tab;
+ a->len = a2->len;
+ a->expn = a2->expn;
+ a->sign = 0;
+
+ /* one more digit for the rounding */
+ n = 1 + bf_mul_log2_radix(bf_max(a->expn, 0), radix, TRUE, TRUE);
+ n_digits = n + prec;
+ n1 = n;
+ if (bf_convert_to_radix(a1, &n1, a, radix, n_digits,
+ flags & BF_RND_MASK, TRUE))
+ goto fail1;
+ start = s->size;
+ output_digits(s, a1, radix, n_digits, n, is_dec);
+ /* remove leading zeros because we allocated one more digit */
+ pos = start;
+ while ((pos + 1) < s->size && s->buf[pos] == '0' &&
+ s->buf[pos + 1] != '.')
+ pos++;
+ if (pos > start) {
+ memmove(s->buf + start, s->buf + pos, s->size - pos);
+ s->size -= (pos - start);
+ }
+ }
+ } else {
+#ifdef USE_BF_DEC
+ if (is_dec) {
+ if (bf_set(a1, a2))
+ goto fail1;
+ if (fmt == BF_FTOA_FORMAT_FIXED) {
+ n_digits = prec;
+ n_max = n_digits;
+ if (bfdec_round((bfdec_t *)a1, prec, (flags & BF_RND_MASK)) & BF_ST_MEM_ERROR)
+ goto fail1;
+ } else {
+ /* prec is ignored */
+ prec = n_digits = a1->len * LIMB_DIGITS;
+ /* remove the trailing zero digits */
+ while (n_digits > 1 &&
+ get_digit(a1->tab, a1->len, prec - n_digits) == 0) {
+ n_digits--;
+ }
+ n_max = n_digits + 4;
+ }
+ n = a1->expn;
+ } else
+#endif
+ if (radix_bits != 0) {
+ if (bf_set(a1, a2))
+ goto fail1;
+ if (fmt == BF_FTOA_FORMAT_FIXED) {
+ slimb_t prec_bits;
+ n_digits = prec;
+ n_max = n_digits;
+ /* align to the radix point */
+ prec_bits = prec * radix_bits -
+ smod(-a1->expn, radix_bits);
+ if (bf_round(a1, prec_bits,
+ (flags & BF_RND_MASK)) & BF_ST_MEM_ERROR)
+ goto fail1;
+ } else {
+ limb_t digit_mask;
+ slimb_t pos;
+ /* position of the digit before the most
+ significant digit in bits */
+ pos = a1->len * LIMB_BITS +
+ smod(-a1->expn, radix_bits);
+ n_digits = ceil_div(pos, radix_bits);
+ /* remove the trailing zero digits */
+ digit_mask = ((limb_t)1 << radix_bits) - 1;
+ while (n_digits > 1 &&
+ (get_bits(a1->tab, a1->len, pos - n_digits * radix_bits) & digit_mask) == 0) {
+ n_digits--;
+ }
+ n_max = n_digits + 4;
+ }
+ n = ceil_div(a1->expn, radix_bits);
+ } else {
+ bf_t a_s, *a = &a_s;
+
+ /* make a positive number */
+ a->tab = a2->tab;
+ a->len = a2->len;
+ a->expn = a2->expn;
+ a->sign = 0;
+
+ if (fmt == BF_FTOA_FORMAT_FIXED) {
+ n_digits = prec;
+ n_max = n_digits;
+ } else {
+ slimb_t n_digits_max, n_digits_min;
+
+ assert(prec != BF_PREC_INF);
+ n_digits = 1 + bf_mul_log2_radix(prec, radix, TRUE, TRUE);
+ /* max number of digits for non exponential
+ notation. The rational is to have the same rule
+ as JS i.e. n_max = 21 for 64 bit float in base 10. */
+ n_max = n_digits + 4;
+ if (fmt == BF_FTOA_FORMAT_FREE_MIN) {
+ bf_t b_s, *b = &b_s;
+
+ /* find the minimum number of digits by
+ dichotomy. */
+ /* XXX: inefficient */
+ n_digits_max = n_digits;
+ n_digits_min = 1;
+ bf_init(ctx, b);
+ while (n_digits_min < n_digits_max) {
+ n_digits = (n_digits_min + n_digits_max) / 2;
+ if (bf_convert_to_radix(a1, &n, a, radix, n_digits,
+ flags & BF_RND_MASK, FALSE)) {
+ bf_delete(b);
+ goto fail1;
+ }
+ /* convert back to a number and compare */
+ ret = bf_mul_pow_radix(b, a1, radix, n - n_digits,
+ prec,
+ (flags & ~BF_RND_MASK) |
+ BF_RNDN);
+ if (ret & BF_ST_MEM_ERROR) {
+ bf_delete(b);
+ goto fail1;
+ }
+ if (bf_cmpu(b, a) == 0) {
+ n_digits_max = n_digits;
+ } else {
+ n_digits_min = n_digits + 1;
+ }
+ }
+ bf_delete(b);
+ n_digits = n_digits_max;
+ }
+ }
+ if (bf_convert_to_radix(a1, &n, a, radix, n_digits,
+ flags & BF_RND_MASK, FALSE)) {
+ fail1:
+ bf_delete(a1);
+ goto fail;
+ }
+ }
+ if (a1->expn == BF_EXP_ZERO &&
+ fmt != BF_FTOA_FORMAT_FIXED &&
+ !(flags & BF_FTOA_FORCE_EXP)) {
+ /* just output zero */
+ dbuf_putstr(s, "0");
+ } else {
+ if (flags & BF_FTOA_ADD_PREFIX) {
+ if (radix == 16)
+ dbuf_putstr(s, "0x");
+ else if (radix == 8)
+ dbuf_putstr(s, "0o");
+ else if (radix == 2)
+ dbuf_putstr(s, "0b");
+ }
+ if (a1->expn == BF_EXP_ZERO)
+ n = 1;
+ if ((flags & BF_FTOA_FORCE_EXP) ||
+ n <= -6 || n > n_max) {
+ const char *fmt;
+ /* exponential notation */
+ output_digits(s, a1, radix, n_digits, 1, is_dec);
+ if (radix_bits != 0 && radix <= 16) {
+ if (flags & BF_FTOA_JS_QUIRKS)
+ fmt = "p%+" PRId_LIMB;
+ else
+ fmt = "p%" PRId_LIMB;
+ dbuf_printf(s, fmt, (n - 1) * radix_bits);
+ } else {
+ if (flags & BF_FTOA_JS_QUIRKS)
+ fmt = "%c%+" PRId_LIMB;
+ else
+ fmt = "%c%" PRId_LIMB;
+ dbuf_printf(s, fmt,
+ radix <= 10 ? 'e' : '@', n - 1);
+ }
+ } else if (n <= 0) {
+ /* 0.x */
+ dbuf_putstr(s, "0.");
+ for(i = 0; i < -n; i++) {
+ dbuf_putc(s, '0');
+ }
+ output_digits(s, a1, radix, n_digits, n_digits, is_dec);
+ } else {
+ if (n_digits <= n) {
+ /* no dot */
+ output_digits(s, a1, radix, n_digits, n_digits, is_dec);
+ for(i = 0; i < (n - n_digits); i++)
+ dbuf_putc(s, '0');
+ } else {
+ output_digits(s, a1, radix, n_digits, n, is_dec);
+ }
+ }
+ }
+ }
+ bf_delete(a1);
+ }
+ }
+ dbuf_putc(s, '\0');
+ if (dbuf_error(s))
+ goto fail;
+ if (plen)
+ *plen = s->size - 1;
+ return (char *)s->buf;
+ fail:
+ bf_free(ctx, s->buf);
+ if (plen)
+ *plen = 0;
+ return NULL;
+}
+
+char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec,
+ bf_flags_t flags)
+{
+ return bf_ftoa_internal(plen, a, radix, prec, flags, FALSE);
+}
+
+/***************************************************************/
+/* transcendental functions */
+
+/* Note: the algorithm is from MPFR */
+static void bf_const_log2_rec(bf_t *T, bf_t *P, bf_t *Q, limb_t n1,
+ limb_t n2, BOOL need_P)
+{
+ bf_context_t *s = T->ctx;
+ if ((n2 - n1) == 1) {
+ if (n1 == 0) {
+ bf_set_ui(P, 3);
+ } else {
+ bf_set_ui(P, n1);
+ P->sign = 1;
+ }
+ bf_set_ui(Q, 2 * n1 + 1);
+ Q->expn += 2;
+ bf_set(T, P);
+ } else {
+ limb_t m;
+ bf_t T1_s, *T1 = &T1_s;
+ bf_t P1_s, *P1 = &P1_s;
+ bf_t Q1_s, *Q1 = &Q1_s;
+
+ m = n1 + ((n2 - n1) >> 1);
+ bf_const_log2_rec(T, P, Q, n1, m, TRUE);
+ bf_init(s, T1);
+ bf_init(s, P1);
+ bf_init(s, Q1);
+ bf_const_log2_rec(T1, P1, Q1, m, n2, need_P);
+ bf_mul(T, T, Q1, BF_PREC_INF, BF_RNDZ);
+ bf_mul(T1, T1, P, BF_PREC_INF, BF_RNDZ);
+ bf_add(T, T, T1, BF_PREC_INF, BF_RNDZ);
+ if (need_P)
+ bf_mul(P, P, P1, BF_PREC_INF, BF_RNDZ);
+ bf_mul(Q, Q, Q1, BF_PREC_INF, BF_RNDZ);
+ bf_delete(T1);
+ bf_delete(P1);
+ bf_delete(Q1);
+ }
+}
+
+/* compute log(2) with faithful rounding at precision 'prec' */
+static void bf_const_log2_internal(bf_t *T, limb_t prec)
+{
+ limb_t w, N;
+ bf_t P_s, *P = &P_s;
+ bf_t Q_s, *Q = &Q_s;
+
+ w = prec + 15;
+ N = w / 3 + 1;
+ bf_init(T->ctx, P);
+ bf_init(T->ctx, Q);
+ bf_const_log2_rec(T, P, Q, 0, N, FALSE);
+ bf_div(T, T, Q, prec, BF_RNDN);
+ bf_delete(P);
+ bf_delete(Q);
+}
+
+/* PI constant */
+
+#define CHUD_A 13591409
+#define CHUD_B 545140134
+#define CHUD_C 640320
+#define CHUD_BITS_PER_TERM 47
+
+static void chud_bs(bf_t *P, bf_t *Q, bf_t *G, int64_t a, int64_t b, int need_g,
+ limb_t prec)
+{
+ bf_context_t *s = P->ctx;
+ int64_t c;
+
+ if (a == (b - 1)) {
+ bf_t T0, T1;
+
+ bf_init(s, &T0);
+ bf_init(s, &T1);
+ bf_set_ui(G, 2 * b - 1);
+ bf_mul_ui(G, G, 6 * b - 1, prec, BF_RNDN);
+ bf_mul_ui(G, G, 6 * b - 5, prec, BF_RNDN);
+ bf_set_ui(&T0, CHUD_B);
+ bf_mul_ui(&T0, &T0, b, prec, BF_RNDN);
+ bf_set_ui(&T1, CHUD_A);
+ bf_add(&T0, &T0, &T1, prec, BF_RNDN);
+ bf_mul(P, G, &T0, prec, BF_RNDN);
+ P->sign = b & 1;
+
+ bf_set_ui(Q, b);
+ bf_mul_ui(Q, Q, b, prec, BF_RNDN);
+ bf_mul_ui(Q, Q, b, prec, BF_RNDN);
+ bf_mul_ui(Q, Q, (uint64_t)CHUD_C * CHUD_C * CHUD_C / 24, prec, BF_RNDN);
+ bf_delete(&T0);
+ bf_delete(&T1);
+ } else {
+ bf_t P2, Q2, G2;
+
+ bf_init(s, &P2);
+ bf_init(s, &Q2);
+ bf_init(s, &G2);
+
+ c = (a + b) / 2;
+ chud_bs(P, Q, G, a, c, 1, prec);
+ chud_bs(&P2, &Q2, &G2, c, b, need_g, prec);
+
+ /* Q = Q1 * Q2 */
+ /* G = G1 * G2 */
+ /* P = P1 * Q2 + P2 * G1 */
+ bf_mul(&P2, &P2, G, prec, BF_RNDN);
+ if (!need_g)
+ bf_set_ui(G, 0);
+ bf_mul(P, P, &Q2, prec, BF_RNDN);
+ bf_add(P, P, &P2, prec, BF_RNDN);
+ bf_delete(&P2);
+
+ bf_mul(Q, Q, &Q2, prec, BF_RNDN);
+ bf_delete(&Q2);
+ if (need_g)
+ bf_mul(G, G, &G2, prec, BF_RNDN);
+ bf_delete(&G2);
+ }
+}
+
+/* compute Pi with faithful rounding at precision 'prec' using the
+ Chudnovsky formula */
+static void bf_const_pi_internal(bf_t *Q, limb_t prec)
+{
+ bf_context_t *s = Q->ctx;
+ int64_t n, prec1;
+ bf_t P, G;
+
+ /* number of serie terms */
+ n = prec / CHUD_BITS_PER_TERM + 1;
+ /* XXX: precision analysis */
+ prec1 = prec + 32;
+
+ bf_init(s, &P);
+ bf_init(s, &G);
+
+ chud_bs(&P, Q, &G, 0, n, 0, BF_PREC_INF);
+
+ bf_mul_ui(&G, Q, CHUD_A, prec1, BF_RNDN);
+ bf_add(&P, &G, &P, prec1, BF_RNDN);
+ bf_div(Q, Q, &P, prec1, BF_RNDF);
+
+ bf_set_ui(&P, CHUD_C);
+ bf_sqrt(&G, &P, prec1, BF_RNDF);
+ bf_mul_ui(&G, &G, (uint64_t)CHUD_C / 12, prec1, BF_RNDF);
+ bf_mul(Q, Q, &G, prec, BF_RNDN);
+ bf_delete(&P);
+ bf_delete(&G);
+}
+
+static int bf_const_get(bf_t *T, limb_t prec, bf_flags_t flags,
+ BFConstCache *c,
+ void (*func)(bf_t *res, limb_t prec), int sign)
+{
+ limb_t ziv_extra_bits, prec1;
+
+ ziv_extra_bits = 32;
+ for(;;) {
+ prec1 = prec + ziv_extra_bits;
+ if (c->prec < prec1) {
+ if (c->val.len == 0)
+ bf_init(T->ctx, &c->val);
+ func(&c->val, prec1);
+ c->prec = prec1;
+ } else {
+ prec1 = c->prec;
+ }
+ bf_set(T, &c->val);
+ T->sign = sign;
+ if (!bf_can_round(T, prec, flags & BF_RND_MASK, prec1)) {
+ /* and more precision and retry */
+ ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2);
+ } else {
+ break;
+ }
+ }
+ return bf_round(T, prec, flags);
+}
+
+static void bf_const_free(BFConstCache *c)
+{
+ bf_delete(&c->val);
+ memset(c, 0, sizeof(*c));
+}
+
+int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags)
+{
+ bf_context_t *s = T->ctx;
+ return bf_const_get(T, prec, flags, &s->log2_cache, bf_const_log2_internal, 0);
+}
+
+/* return rounded pi * (1 - 2 * sign) */
+static int bf_const_pi_signed(bf_t *T, int sign, limb_t prec, bf_flags_t flags)
+{
+ bf_context_t *s = T->ctx;
+ return bf_const_get(T, prec, flags, &s->pi_cache, bf_const_pi_internal,
+ sign);
+}
+
+int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags)
+{
+ return bf_const_pi_signed(T, 0, prec, flags);
+}
+
+void bf_clear_cache(bf_context_t *s)
+{
+#ifdef USE_FFT_MUL
+ fft_clear_cache(s);
+#endif
+ bf_const_free(&s->log2_cache);
+ bf_const_free(&s->pi_cache);
+}
+
+/* ZivFunc should compute the result 'r' with faithful rounding at
+ precision 'prec'. For efficiency purposes, the final bf_round()
+ does not need to be done in the function. */
+typedef int ZivFunc(bf_t *r, const bf_t *a, limb_t prec, void *opaque);
+
+static int bf_ziv_rounding(bf_t *r, const bf_t *a,
+ limb_t prec, bf_flags_t flags,
+ ZivFunc *f, void *opaque)
+{
+ int rnd_mode, ret;
+ slimb_t prec1, ziv_extra_bits;
+
+ rnd_mode = flags & BF_RND_MASK;
+ if (rnd_mode == BF_RNDF) {
+ /* no need to iterate */
+ f(r, a, prec, opaque);
+ ret = 0;
+ } else {
+ ziv_extra_bits = 32;
+ for(;;) {
+ prec1 = prec + ziv_extra_bits;
+ ret = f(r, a, prec1, opaque);
+ if (ret & (BF_ST_OVERFLOW | BF_ST_UNDERFLOW | BF_ST_MEM_ERROR)) {
+ /* overflow or underflow should never happen because
+ it indicates the rounding cannot be done correctly,
+ but we do not catch all the cases */
+ return ret;
+ }
+ /* if the result is exact, we can stop */
+ if (!(ret & BF_ST_INEXACT)) {
+ ret = 0;
+ break;
+ }
+ if (bf_can_round(r, prec, rnd_mode, prec1)) {
+ ret = BF_ST_INEXACT;
+ break;
+ }
+ ziv_extra_bits = ziv_extra_bits * 2;
+ // printf("ziv_extra_bits=%" PRId64 "\n", (int64_t)ziv_extra_bits);
+ }
+ }
+ if (r->len == 0)
+ return ret;
+ else
+ return __bf_round(r, prec, flags, r->len, ret);
+}
+
+/* add (1 - 2*e_sign) * 2^e */
+static int bf_add_epsilon(bf_t *r, const bf_t *a, slimb_t e, int e_sign,
+ limb_t prec, int flags)
+{
+ bf_t T_s, *T = &T_s;
+ int ret;
+ /* small argument case: result = 1 + epsilon * sign(x) */
+ bf_init(a->ctx, T);
+ bf_set_ui(T, 1);
+ T->sign = e_sign;
+ T->expn += e;
+ ret = bf_add(r, r, T, prec, flags);
+ bf_delete(T);
+ return ret;
+}
+
+/* Compute the exponential using faithful rounding at precision 'prec'.
+ Note: the algorithm is from MPFR */
+static int bf_exp_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)
+{
+ bf_context_t *s = r->ctx;
+ bf_t T_s, *T = &T_s;
+ slimb_t n, K, l, i, prec1;
+
+ assert(r != a);
+
+ /* argument reduction:
+ T = a - n*log(2) with 0 <= T < log(2) and n integer.
+ */
+ bf_init(s, T);
+ if (a->expn <= -1) {
+ /* 0 <= abs(a) <= 0.5 */
+ if (a->sign)
+ n = -1;
+ else
+ n = 0;
+ } else {
+ bf_const_log2(T, LIMB_BITS, BF_RNDZ);
+ bf_div(T, a, T, LIMB_BITS, BF_RNDD);
+ bf_get_limb(&n, T, 0);
+ }
+
+ K = bf_isqrt((prec + 1) / 2);
+ l = (prec - 1) / K + 1;
+ /* XXX: precision analysis ? */
+ prec1 = prec + (K + 2 * l + 18) + K + 8;
+ if (a->expn > 0)
+ prec1 += a->expn;
+ // printf("n=%ld K=%ld prec1=%ld\n", n, K, prec1);
+
+ bf_const_log2(T, prec1, BF_RNDF);
+ bf_mul_si(T, T, n, prec1, BF_RNDN);
+ bf_sub(T, a, T, prec1, BF_RNDN);
+
+ /* reduce the range of T */
+ bf_mul_2exp(T, -K, BF_PREC_INF, BF_RNDZ);
+
+ /* Taylor expansion around zero :
+ 1 + x + x^2/2 + ... + x^n/n!
+ = (1 + x * (1 + x/2 * (1 + ... (x/n))))
+ */
+ {
+ bf_t U_s, *U = &U_s;
+
+ bf_init(s, U);
+ bf_set_ui(r, 1);
+ for(i = l ; i >= 1; i--) {
+ bf_set_ui(U, i);
+ bf_div(U, T, U, prec1, BF_RNDN);
+ bf_mul(r, r, U, prec1, BF_RNDN);
+ bf_add_si(r, r, 1, prec1, BF_RNDN);
+ }
+ bf_delete(U);
+ }
+ bf_delete(T);
+
+ /* undo the range reduction */
+ for(i = 0; i < K; i++) {
+ bf_mul(r, r, r, prec1, BF_RNDN | BF_FLAG_EXT_EXP);
+ }
+
+ /* undo the argument reduction */
+ bf_mul_2exp(r, n, BF_PREC_INF, BF_RNDZ | BF_FLAG_EXT_EXP);
+
+ return BF_ST_INEXACT;
+}
+
+/* crude overflow and underflow tests for exp(a). a_low <= a <= a_high */
+static int check_exp_underflow_overflow(bf_context_t *s, bf_t *r,
+ const bf_t *a_low, const bf_t *a_high,
+ limb_t prec, bf_flags_t flags)
+{
+ bf_t T_s, *T = &T_s;
+ bf_t log2_s, *log2 = &log2_s;
+ slimb_t e_min, e_max;
+
+ if (a_high->expn <= 0)
+ return 0;
+
+ e_max = (limb_t)1 << (bf_get_exp_bits(flags) - 1);
+ e_min = -e_max + 3;
+ if (flags & BF_FLAG_SUBNORMAL)
+ e_min -= (prec - 1);
+
+ bf_init(s, T);
+ bf_init(s, log2);
+ bf_const_log2(log2, LIMB_BITS, BF_RNDU);
+ bf_mul_ui(T, log2, e_max, LIMB_BITS, BF_RNDU);
+ /* a_low > e_max * log(2) implies exp(a) > e_max */
+ if (bf_cmp_lt(T, a_low) > 0) {
+ /* overflow */
+ bf_delete(T);
+ bf_delete(log2);
+ return bf_set_overflow(r, 0, prec, flags);
+ }
+ /* a_high < (e_min - 2) * log(2) implies exp(a) < (e_min - 2) */
+ bf_const_log2(log2, LIMB_BITS, BF_RNDD);
+ bf_mul_si(T, log2, e_min - 2, LIMB_BITS, BF_RNDD);
+ if (bf_cmp_lt(a_high, T)) {
+ int rnd_mode = flags & BF_RND_MASK;
+
+ /* underflow */
+ bf_delete(T);
+ bf_delete(log2);
+ if (rnd_mode == BF_RNDU) {
+ /* set the smallest value */
+ bf_set_ui(r, 1);
+ r->expn = e_min;
+ } else {
+ bf_set_zero(r, 0);
+ }
+ return BF_ST_UNDERFLOW | BF_ST_INEXACT;
+ }
+ bf_delete(log2);
+ bf_delete(T);
+ return 0;
+}
+
+int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
+{
+ bf_context_t *s = r->ctx;
+ int ret;
+ assert(r != a);
+ if (a->len == 0) {
+ if (a->expn == BF_EXP_NAN) {
+ bf_set_nan(r);
+ } else if (a->expn == BF_EXP_INF) {
+ if (a->sign)
+ bf_set_zero(r, 0);
+ else
+ bf_set_inf(r, 0);
+ } else {
+ bf_set_ui(r, 1);
+ }
+ return 0;
+ }
+
+ ret = check_exp_underflow_overflow(s, r, a, a, prec, flags);
+ if (ret)
+ return ret;
+ if (a->expn < 0 && (-a->expn) >= (prec + 2)) {
+ /* small argument case: result = 1 + epsilon * sign(x) */
+ bf_set_ui(r, 1);
+ return bf_add_epsilon(r, r, -(prec + 2), a->sign, prec, flags);
+ }
+
+ return bf_ziv_rounding(r, a, prec, flags, bf_exp_internal, NULL);
+}
+
+static int bf_log_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)
+{
+ bf_context_t *s = r->ctx;
+ bf_t T_s, *T = &T_s;
+ bf_t U_s, *U = &U_s;
+ bf_t V_s, *V = &V_s;
+ slimb_t n, prec1, l, i, K;
+
+ assert(r != a);
+
+ bf_init(s, T);
+ /* argument reduction 1 */
+ /* T=a*2^n with 2/3 <= T <= 4/3 */
+ {
+ bf_t U_s, *U = &U_s;
+ bf_set(T, a);
+ n = T->expn;
+ T->expn = 0;
+ /* U= ~ 2/3 */
+ bf_init(s, U);
+ bf_set_ui(U, 0xaaaaaaaa);
+ U->expn = 0;
+ if (bf_cmp_lt(T, U)) {
+ T->expn++;
+ n--;
+ }
+ bf_delete(U);
+ }
+ // printf("n=%ld\n", n);
+ // bf_print_str("T", T);
+
+ /* XXX: precision analysis */
+ /* number of iterations for argument reduction 2 */
+ K = bf_isqrt((prec + 1) / 2);
+ /* order of Taylor expansion */
+ l = prec / (2 * K) + 1;
+ /* precision of the intermediate computations */
+ prec1 = prec + K + 2 * l + 32;
+
+ bf_init(s, U);
+ bf_init(s, V);
+
+ /* Note: cancellation occurs here, so we use more precision (XXX:
+ reduce the precision by computing the exact cancellation) */
+ bf_add_si(T, T, -1, BF_PREC_INF, BF_RNDN);
+
+ /* argument reduction 2 */
+ for(i = 0; i < K; i++) {
+ /* T = T / (1 + sqrt(1 + T)) */
+ bf_add_si(U, T, 1, prec1, BF_RNDN);
+ bf_sqrt(V, U, prec1, BF_RNDF);
+ bf_add_si(U, V, 1, prec1, BF_RNDN);
+ bf_div(T, T, U, prec1, BF_RNDN);
+ }
+
+ {
+ bf_t Y_s, *Y = &Y_s;
+ bf_t Y2_s, *Y2 = &Y2_s;
+ bf_init(s, Y);
+ bf_init(s, Y2);
+
+ /* compute ln(1+x) = ln((1+y)/(1-y)) with y=x/(2+x)
+ = y + y^3/3 + ... + y^(2*l + 1) / (2*l+1)
+ with Y=Y^2
+ = y*(1+Y/3+Y^2/5+...) = y*(1+Y*(1/3+Y*(1/5 + ...)))
+ */
+ bf_add_si(Y, T, 2, prec1, BF_RNDN);
+ bf_div(Y, T, Y, prec1, BF_RNDN);
+
+ bf_mul(Y2, Y, Y, prec1, BF_RNDN);
+ bf_set_ui(r, 0);
+ for(i = l; i >= 1; i--) {
+ bf_set_ui(U, 1);
+ bf_set_ui(V, 2 * i + 1);
+ bf_div(U, U, V, prec1, BF_RNDN);
+ bf_add(r, r, U, prec1, BF_RNDN);
+ bf_mul(r, r, Y2, prec1, BF_RNDN);
+ }
+ bf_add_si(r, r, 1, prec1, BF_RNDN);
+ bf_mul(r, r, Y, prec1, BF_RNDN);
+ bf_delete(Y);
+ bf_delete(Y2);
+ }
+ bf_delete(V);
+ bf_delete(U);
+
+ /* multiplication by 2 for the Taylor expansion and undo the
+ argument reduction 2*/
+ bf_mul_2exp(r, K + 1, BF_PREC_INF, BF_RNDZ);
+
+ /* undo the argument reduction 1 */
+ bf_const_log2(T, prec1, BF_RNDF);
+ bf_mul_si(T, T, n, prec1, BF_RNDN);
+ bf_add(r, r, T, prec1, BF_RNDN);
+
+ bf_delete(T);
+ return BF_ST_INEXACT;
+}
+
+int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
+{
+ bf_context_t *s = r->ctx;
+ bf_t T_s, *T = &T_s;
+
+ assert(r != a);
+ if (a->len == 0) {
+ if (a->expn == BF_EXP_NAN) {
+ bf_set_nan(r);
+ return 0;
+ } else if (a->expn == BF_EXP_INF) {
+ if (a->sign) {
+ bf_set_nan(r);
+ return BF_ST_INVALID_OP;
+ } else {
+ bf_set_inf(r, 0);
+ return 0;
+ }
+ } else {
+ bf_set_inf(r, 1);
+ return 0;
+ }
+ }
+ if (a->sign) {
+ bf_set_nan(r);
+ return BF_ST_INVALID_OP;
+ }
+ bf_init(s, T);
+ bf_set_ui(T, 1);
+ if (bf_cmp_eq(a, T)) {
+ bf_set_zero(r, 0);
+ bf_delete(T);
+ return 0;
+ }
+ bf_delete(T);
+
+ return bf_ziv_rounding(r, a, prec, flags, bf_log_internal, NULL);
+}
+
+/* x and y finite and x > 0 */
+static int bf_pow_generic(bf_t *r, const bf_t *x, limb_t prec, void *opaque)
+{
+ bf_context_t *s = r->ctx;
+ const bf_t *y = opaque;
+ bf_t T_s, *T = &T_s;
+ limb_t prec1;
+
+ bf_init(s, T);
+ /* XXX: proof for the added precision */
+ prec1 = prec + 32;
+ bf_log(T, x, prec1, BF_RNDF | BF_FLAG_EXT_EXP);
+ bf_mul(T, T, y, prec1, BF_RNDF | BF_FLAG_EXT_EXP);
+ if (bf_is_nan(T))
+ bf_set_nan(r);
+ else
+ bf_exp_internal(r, T, prec1, NULL); /* no overflow/underlow test needed */
+ bf_delete(T);
+ return BF_ST_INEXACT;
+}
+
+/* x and y finite, x > 0, y integer and y fits on one limb */
+static int bf_pow_int(bf_t *r, const bf_t *x, limb_t prec, void *opaque)
+{
+ bf_context_t *s = r->ctx;
+ const bf_t *y = opaque;
+ bf_t T_s, *T = &T_s;
+ limb_t prec1;
+ int ret;
+ slimb_t y1;
+
+ bf_get_limb(&y1, y, 0);
+ if (y1 < 0)
+ y1 = -y1;
+ /* XXX: proof for the added precision */
+ prec1 = prec + ceil_log2(y1) * 2 + 8;
+ ret = bf_pow_ui(r, x, y1 < 0 ? -y1 : y1, prec1, BF_RNDN | BF_FLAG_EXT_EXP);
+ if (y->sign) {
+ bf_init(s, T);
+ bf_set_ui(T, 1);
+ ret |= bf_div(r, T, r, prec1, BF_RNDN | BF_FLAG_EXT_EXP);
+ bf_delete(T);
+ }
+ return ret;
+}
+
+/* x must be a finite non zero float. Return TRUE if there is a
+ floating point number r such as x=r^(2^n) and return this floating
+ point number 'r'. Otherwise return FALSE and r is undefined. */
+static BOOL check_exact_power2n(bf_t *r, const bf_t *x, slimb_t n)
+{
+ bf_context_t *s = r->ctx;
+ bf_t T_s, *T = &T_s;
+ slimb_t e, i, er;
+ limb_t v;
+
+ /* x = m*2^e with m odd integer */
+ e = bf_get_exp_min(x);
+ /* fast check on the exponent */
+ if (n > (LIMB_BITS - 1)) {
+ if (e != 0)
+ return FALSE;
+ er = 0;
+ } else {
+ if ((e & (((limb_t)1 << n) - 1)) != 0)
+ return FALSE;
+ er = e >> n;
+ }
+ /* every perfect odd square = 1 modulo 8 */
+ v = get_bits(x->tab, x->len, x->len * LIMB_BITS - x->expn + e);
+ if ((v & 7) != 1)
+ return FALSE;
+
+ bf_init(s, T);
+ bf_set(T, x);
+ T->expn -= e;
+ for(i = 0; i < n; i++) {
+ if (i != 0)
+ bf_set(T, r);
+ if (bf_sqrtrem(r, NULL, T) != 0)
+ return FALSE;
+ }
+ r->expn += er;
+ return TRUE;
+}
+
+/* prec = BF_PREC_INF is accepted for x and y integers and y >= 0 */
+int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags)
+{
+ bf_context_t *s = r->ctx;
+ bf_t T_s, *T = &T_s;
+ bf_t ytmp_s;
+ BOOL y_is_int, y_is_odd;
+ int r_sign, ret, rnd_mode;
+ slimb_t y_emin;
+
+ if (x->len == 0 || y->len == 0) {
+ if (y->expn == BF_EXP_ZERO) {
+ /* pow(x, 0) = 1 */
+ bf_set_ui(r, 1);
+ } else if (x->expn == BF_EXP_NAN) {
+ bf_set_nan(r);
+ } else {
+ int cmp_x_abs_1;
+ bf_set_ui(r, 1);
+ cmp_x_abs_1 = bf_cmpu(x, r);
+ if (cmp_x_abs_1 == 0 && (flags & BF_POW_JS_QUIRKS) &&
+ (y->expn >= BF_EXP_INF)) {
+ bf_set_nan(r);
+ } else if (cmp_x_abs_1 == 0 &&
+ (!x->sign || y->expn != BF_EXP_NAN)) {
+ /* pow(1, y) = 1 even if y = NaN */
+ /* pow(-1, +/-inf) = 1 */
+ } else if (y->expn == BF_EXP_NAN) {
+ bf_set_nan(r);
+ } else if (y->expn == BF_EXP_INF) {
+ if (y->sign == (cmp_x_abs_1 > 0)) {
+ bf_set_zero(r, 0);
+ } else {
+ bf_set_inf(r, 0);
+ }
+ } else {
+ y_emin = bf_get_exp_min(y);
+ y_is_odd = (y_emin == 0);
+ if (y->sign == (x->expn == BF_EXP_ZERO)) {
+ bf_set_inf(r, y_is_odd & x->sign);
+ if (y->sign) {
+ /* pow(0, y) with y < 0 */
+ return BF_ST_DIVIDE_ZERO;
+ }
+ } else {
+ bf_set_zero(r, y_is_odd & x->sign);
+ }
+ }
+ }
+ return 0;
+ }
+ bf_init(s, T);
+ bf_set(T, x);
+ y_emin = bf_get_exp_min(y);
+ y_is_int = (y_emin >= 0);
+ rnd_mode = flags & BF_RND_MASK;
+ if (x->sign) {
+ if (!y_is_int) {
+ bf_set_nan(r);
+ bf_delete(T);
+ return BF_ST_INVALID_OP;
+ }
+ y_is_odd = (y_emin == 0);
+ r_sign = y_is_odd;
+ /* change the directed rounding mode if the sign of the result
+ is changed */
+ if (r_sign && (rnd_mode == BF_RNDD || rnd_mode == BF_RNDU))
+ flags ^= 1;
+ bf_neg(T);
+ } else {
+ r_sign = 0;
+ }
+
+ bf_set_ui(r, 1);
+ if (bf_cmp_eq(T, r)) {
+ /* abs(x) = 1: nothing more to do */
+ ret = 0;
+ } else {
+ /* check the overflow/underflow cases */
+ {
+ bf_t al_s, *al = &al_s;
+ bf_t ah_s, *ah = &ah_s;
+ limb_t precl = LIMB_BITS;
+
+ bf_init(s, al);
+ bf_init(s, ah);
+ /* compute bounds of log(abs(x)) * y with a low precision */
+ /* XXX: compute bf_log() once */
+ /* XXX: add a fast test before this slow test */
+ bf_log(al, T, precl, BF_RNDD);
+ bf_log(ah, T, precl, BF_RNDU);
+ bf_mul(al, al, y, precl, BF_RNDD ^ y->sign);
+ bf_mul(ah, ah, y, precl, BF_RNDU ^ y->sign);
+ ret = check_exp_underflow_overflow(s, r, al, ah, prec, flags);
+ bf_delete(al);
+ bf_delete(ah);
+ if (ret)
+ goto done;
+ }
+
+ if (y_is_int) {
+ slimb_t T_bits, e;
+ int_pow:
+ T_bits = T->expn - bf_get_exp_min(T);
+ if (T_bits == 1) {
+ /* pow(2^b, y) = 2^(b*y) */
+ bf_mul_si(T, y, T->expn - 1, LIMB_BITS, BF_RNDZ);
+ bf_get_limb(&e, T, 0);
+ bf_set_ui(r, 1);
+ ret = bf_mul_2exp(r, e, prec, flags);
+ } else if (prec == BF_PREC_INF) {
+ slimb_t y1;
+ /* specific case for infinite precision (integer case) */
+ bf_get_limb(&y1, y, 0);
+ assert(!y->sign);
+ /* x must be an integer, so abs(x) >= 2 */
+ if (y1 >= ((slimb_t)1 << BF_EXP_BITS_MAX)) {
+ bf_delete(T);
+ return bf_set_overflow(r, 0, BF_PREC_INF, flags);
+ }
+ ret = bf_pow_ui(r, T, y1, BF_PREC_INF, BF_RNDZ);
+ } else {
+ if (y->expn <= 31) {
+ /* small enough power: use exponentiation in all cases */
+ } else if (y->sign) {
+ /* cannot be exact */
+ goto general_case;
+ } else {
+ if (rnd_mode == BF_RNDF)
+ goto general_case; /* no need to track exact results */
+ /* see if the result has a chance to be exact:
+ if x=a*2^b (a odd), x^y=a^y*2^(b*y)
+ x^y needs a precision of at least floor_log2(a)*y bits
+ */
+ bf_mul_si(r, y, T_bits - 1, LIMB_BITS, BF_RNDZ);
+ bf_get_limb(&e, r, 0);
+ if (prec < e)
+ goto general_case;
+ }
+ ret = bf_ziv_rounding(r, T, prec, flags, bf_pow_int, (void *)y);
+ }
+ } else {
+ if (rnd_mode != BF_RNDF) {
+ bf_t *y1;
+ if (y_emin < 0 && check_exact_power2n(r, T, -y_emin)) {
+ /* the problem is reduced to a power to an integer */
+#if 0
+ printf("\nn=%" PRId64 "\n", -(int64_t)y_emin);
+ bf_print_str("T", T);
+ bf_print_str("r", r);
+#endif
+ bf_set(T, r);
+ y1 = &ytmp_s;
+ y1->tab = y->tab;
+ y1->len = y->len;
+ y1->sign = y->sign;
+ y1->expn = y->expn - y_emin;
+ y = y1;
+ goto int_pow;
+ }
+ }
+ general_case:
+ ret = bf_ziv_rounding(r, T, prec, flags, bf_pow_generic, (void *)y);
+ }
+ }
+ done:
+ bf_delete(T);
+ r->sign = r_sign;
+ return ret;
+}
+
+/* compute sqrt(-2*x-x^2) to get |sin(x)| from cos(x) - 1. */
+static void bf_sqrt_sin(bf_t *r, const bf_t *x, limb_t prec1)
+{
+ bf_context_t *s = r->ctx;
+ bf_t T_s, *T = &T_s;
+ bf_init(s, T);
+ bf_set(T, x);
+ bf_mul(r, T, T, prec1, BF_RNDN);
+ bf_mul_2exp(T, 1, BF_PREC_INF, BF_RNDZ);
+ bf_add(T, T, r, prec1, BF_RNDN);
+ bf_neg(T);
+ bf_sqrt(r, T, prec1, BF_RNDF);
+ bf_delete(T);
+}
+
+static int bf_sincos(bf_t *s, bf_t *c, const bf_t *a, limb_t prec)
+{
+ bf_context_t *s1 = a->ctx;
+ bf_t T_s, *T = &T_s;
+ bf_t U_s, *U = &U_s;
+ bf_t r_s, *r = &r_s;
+ slimb_t K, prec1, i, l, mod, prec2;
+ int is_neg;
+
+ assert(c != a && s != a);
+
+ bf_init(s1, T);
+ bf_init(s1, U);
+ bf_init(s1, r);
+
+ /* XXX: precision analysis */
+ K = bf_isqrt(prec / 2);
+ l = prec / (2 * K) + 1;
+ prec1 = prec + 2 * K + l + 8;
+
+ /* after the modulo reduction, -pi/4 <= T <= pi/4 */
+ if (a->expn <= -1) {
+ /* abs(a) <= 0.25: no modulo reduction needed */
+ bf_set(T, a);
+ mod = 0;
+ } else {
+ slimb_t cancel;
+ cancel = 0;
+ for(;;) {
+ prec2 = prec1 + a->expn + cancel;
+ bf_const_pi(U, prec2, BF_RNDF);
+ bf_mul_2exp(U, -1, BF_PREC_INF, BF_RNDZ);
+ bf_remquo(&mod, T, a, U, prec2, BF_RNDN, BF_RNDN);
+ // printf("T.expn=%ld prec2=%ld\n", T->expn, prec2);
+ if (mod == 0 || (T->expn != BF_EXP_ZERO &&
+ (T->expn + prec2) >= (prec1 - 1)))
+ break;
+ /* increase the number of bits until the precision is good enough */
+ cancel = bf_max(-T->expn, (cancel + 1) * 3 / 2);
+ }
+ mod &= 3;
+ }
+
+ is_neg = T->sign;
+
+ /* compute cosm1(x) = cos(x) - 1 */
+ bf_mul(T, T, T, prec1, BF_RNDN);
+ bf_mul_2exp(T, -2 * K, BF_PREC_INF, BF_RNDZ);
+
+ /* Taylor expansion:
+ -x^2/2 + x^4/4! - x^6/6! + ...
+ */
+ bf_set_ui(r, 1);
+ for(i = l ; i >= 1; i--) {
+ bf_set_ui(U, 2 * i - 1);
+ bf_mul_ui(U, U, 2 * i, BF_PREC_INF, BF_RNDZ);
+ bf_div(U, T, U, prec1, BF_RNDN);
+ bf_mul(r, r, U, prec1, BF_RNDN);
+ bf_neg(r);
+ if (i != 1)
+ bf_add_si(r, r, 1, prec1, BF_RNDN);
+ }
+ bf_delete(U);
+
+ /* undo argument reduction:
+ cosm1(2*x)= 2*(2*cosm1(x)+cosm1(x)^2)
+ */
+ for(i = 0; i < K; i++) {
+ bf_mul(T, r, r, prec1, BF_RNDN);
+ bf_mul_2exp(r, 1, BF_PREC_INF, BF_RNDZ);
+ bf_add(r, r, T, prec1, BF_RNDN);
+ bf_mul_2exp(r, 1, BF_PREC_INF, BF_RNDZ);
+ }
+ bf_delete(T);
+
+ if (c) {
+ if ((mod & 1) == 0) {
+ bf_add_si(c, r, 1, prec1, BF_RNDN);
+ } else {
+ bf_sqrt_sin(c, r, prec1);
+ c->sign = is_neg ^ 1;
+ }
+ c->sign ^= mod >> 1;
+ }
+ if (s) {
+ if ((mod & 1) == 0) {
+ bf_sqrt_sin(s, r, prec1);
+ s->sign = is_neg;
+ } else {
+ bf_add_si(s, r, 1, prec1, BF_RNDN);
+ }
+ s->sign ^= mod >> 1;
+ }
+ bf_delete(r);
+ return BF_ST_INEXACT;
+}
+
+static int bf_cos_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)
+{
+ return bf_sincos(NULL, r, a, prec);
+}
+
+int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
+{
+ if (a->len == 0) {
+ if (a->expn == BF_EXP_NAN) {
+ bf_set_nan(r);
+ return 0;
+ } else if (a->expn == BF_EXP_INF) {
+ bf_set_nan(r);
+ return BF_ST_INVALID_OP;
+ } else {
+ bf_set_ui(r, 1);
+ return 0;
+ }
+ }
+
+ /* small argument case: result = 1+r(x) with r(x) = -x^2/2 +
+ O(X^4). We assume r(x) < 2^(2*EXP(x) - 1). */
+ if (a->expn < 0) {
+ slimb_t e;
+ e = 2 * a->expn - 1;
+ if (e < -(prec + 2)) {
+ bf_set_ui(r, 1);
+ return bf_add_epsilon(r, r, e, 1, prec, flags);
+ }
+ }
+
+ return bf_ziv_rounding(r, a, prec, flags, bf_cos_internal, NULL);
+}
+
+static int bf_sin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)
+{
+ return bf_sincos(r, NULL, a, prec);
+}
+
+int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
+{
+ if (a->len == 0) {
+ if (a->expn == BF_EXP_NAN) {
+ bf_set_nan(r);
+ return 0;
+ } else if (a->expn == BF_EXP_INF) {
+ bf_set_nan(r);
+ return BF_ST_INVALID_OP;
+ } else {
+ bf_set_zero(r, a->sign);
+ return 0;
+ }
+ }
+
+ /* small argument case: result = x+r(x) with r(x) = -x^3/6 +
+ O(X^5). We assume r(x) < 2^(3*EXP(x) - 2). */
+ if (a->expn < 0) {
+ slimb_t e;
+ e = sat_add(2 * a->expn, a->expn - 2);
+ if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {
+ bf_set(r, a);
+ return bf_add_epsilon(r, r, e, 1 - a->sign, prec, flags);
+ }
+ }
+
+ return bf_ziv_rounding(r, a, prec, flags, bf_sin_internal, NULL);
+}
+
+static int bf_tan_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)
+{
+ bf_context_t *s = r->ctx;
+ bf_t T_s, *T = &T_s;
+ limb_t prec1;
+
+ /* XXX: precision analysis */
+ prec1 = prec + 8;
+ bf_init(s, T);
+ bf_sincos(r, T, a, prec1);
+ bf_div(r, r, T, prec1, BF_RNDF);
+ bf_delete(T);
+ return BF_ST_INEXACT;
+}
+
+int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
+{
+ assert(r != a);
+ if (a->len == 0) {
+ if (a->expn == BF_EXP_NAN) {
+ bf_set_nan(r);
+ return 0;
+ } else if (a->expn == BF_EXP_INF) {
+ bf_set_nan(r);
+ return BF_ST_INVALID_OP;
+ } else {
+ bf_set_zero(r, a->sign);
+ return 0;
+ }
+ }
+
+ /* small argument case: result = x+r(x) with r(x) = x^3/3 +
+ O(X^5). We assume r(x) < 2^(3*EXP(x) - 1). */
+ if (a->expn < 0) {
+ slimb_t e;
+ e = sat_add(2 * a->expn, a->expn - 1);
+ if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {
+ bf_set(r, a);
+ return bf_add_epsilon(r, r, e, a->sign, prec, flags);
+ }
+ }
+
+ return bf_ziv_rounding(r, a, prec, flags, bf_tan_internal, NULL);
+}
+
+/* if add_pi2 is true, add pi/2 to the result (used for acos(x) to
+ avoid cancellation) */
+static int bf_atan_internal(bf_t *r, const bf_t *a, limb_t prec,
+ void *opaque)
+{
+ bf_context_t *s = r->ctx;
+ BOOL add_pi2 = (BOOL)(intptr_t)opaque;
+ bf_t T_s, *T = &T_s;
+ bf_t U_s, *U = &U_s;
+ bf_t V_s, *V = &V_s;
+ bf_t X2_s, *X2 = &X2_s;
+ int cmp_1;
+ slimb_t prec1, i, K, l;
+
+ /* XXX: precision analysis */
+ K = bf_isqrt((prec + 1) / 2);
+ l = prec / (2 * K) + 1;
+ prec1 = prec + K + 2 * l + 32;
+ // printf("prec=%d K=%d l=%d prec1=%d\n", (int)prec, (int)K, (int)l, (int)prec1);
+
+ bf_init(s, T);
+ cmp_1 = (a->expn >= 1); /* a >= 1 */
+ if (cmp_1) {
+ bf_set_ui(T, 1);
+ bf_div(T, T, a, prec1, BF_RNDN);
+ } else {
+ bf_set(T, a);
+ }
+
+ /* abs(T) <= 1 */
+
+ /* argument reduction */
+
+ bf_init(s, U);
+ bf_init(s, V);
+ bf_init(s, X2);
+ for(i = 0; i < K; i++) {
+ /* T = T / (1 + sqrt(1 + T^2)) */
+ bf_mul(U, T, T, prec1, BF_RNDN);
+ bf_add_si(U, U, 1, prec1, BF_RNDN);
+ bf_sqrt(V, U, prec1, BF_RNDN);
+ bf_add_si(V, V, 1, prec1, BF_RNDN);
+ bf_div(T, T, V, prec1, BF_RNDN);
+ }
+
+ /* Taylor series:
+ x - x^3/3 + ... + (-1)^ l * y^(2*l + 1) / (2*l+1)
+ */
+ bf_mul(X2, T, T, prec1, BF_RNDN);
+ bf_set_ui(r, 0);
+ for(i = l; i >= 1; i--) {
+ bf_set_si(U, 1);
+ bf_set_ui(V, 2 * i + 1);
+ bf_div(U, U, V, prec1, BF_RNDN);
+ bf_neg(r);
+ bf_add(r, r, U, prec1, BF_RNDN);
+ bf_mul(r, r, X2, prec1, BF_RNDN);
+ }
+ bf_neg(r);
+ bf_add_si(r, r, 1, prec1, BF_RNDN);
+ bf_mul(r, r, T, prec1, BF_RNDN);
+
+ /* undo the argument reduction */
+ bf_mul_2exp(r, K, BF_PREC_INF, BF_RNDZ);
+
+ bf_delete(U);
+ bf_delete(V);
+ bf_delete(X2);
+
+ i = add_pi2;
+ if (cmp_1 > 0) {
+ /* undo the inversion : r = sign(a)*PI/2 - r */
+ bf_neg(r);
+ i += 1 - 2 * a->sign;
+ }
+ /* add i*(pi/2) with -1 <= i <= 2 */
+ if (i != 0) {
+ bf_const_pi(T, prec1, BF_RNDF);
+ if (i != 2)
+ bf_mul_2exp(T, -1, BF_PREC_INF, BF_RNDZ);
+ T->sign = (i < 0);
+ bf_add(r, T, r, prec1, BF_RNDN);
+ }
+
+ bf_delete(T);
+ return BF_ST_INEXACT;
+}
+
+int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
+{
+ bf_context_t *s = r->ctx;
+ bf_t T_s, *T = &T_s;
+ int res;
+
+ if (a->len == 0) {
+ if (a->expn == BF_EXP_NAN) {
+ bf_set_nan(r);
+ return 0;
+ } else if (a->expn == BF_EXP_INF) {
+ /* -PI/2 or PI/2 */
+ bf_const_pi_signed(r, a->sign, prec, flags);
+ bf_mul_2exp(r, -1, BF_PREC_INF, BF_RNDZ);
+ return BF_ST_INEXACT;
+ } else {
+ bf_set_zero(r, a->sign);
+ return 0;
+ }
+ }
+
+ bf_init(s, T);
+ bf_set_ui(T, 1);
+ res = bf_cmpu(a, T);
+ bf_delete(T);
+ if (res == 0) {
+ /* short cut: abs(a) == 1 -> +/-pi/4 */
+ bf_const_pi_signed(r, a->sign, prec, flags);
+ bf_mul_2exp(r, -2, BF_PREC_INF, BF_RNDZ);
+ return BF_ST_INEXACT;
+ }
+
+ /* small argument case: result = x+r(x) with r(x) = -x^3/3 +
+ O(X^5). We assume r(x) < 2^(3*EXP(x) - 1). */
+ if (a->expn < 0) {
+ slimb_t e;
+ e = sat_add(2 * a->expn, a->expn - 1);
+ if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {
+ bf_set(r, a);
+ return bf_add_epsilon(r, r, e, 1 - a->sign, prec, flags);
+ }
+ }
+
+ return bf_ziv_rounding(r, a, prec, flags, bf_atan_internal, (void *)FALSE);
+}
+
+static int bf_atan2_internal(bf_t *r, const bf_t *y, limb_t prec, void *opaque)
+{
+ bf_context_t *s = r->ctx;
+ const bf_t *x = opaque;
+ bf_t T_s, *T = &T_s;
+ limb_t prec1;
+ int ret;
+
+ if (y->expn == BF_EXP_NAN || x->expn == BF_EXP_NAN) {
+ bf_set_nan(r);
+ return 0;
+ }
+
+ /* compute atan(y/x) assumming inf/inf = 1 and 0/0 = 0 */
+ bf_init(s, T);
+ prec1 = prec + 32;
+ if (y->expn == BF_EXP_INF && x->expn == BF_EXP_INF) {
+ bf_set_ui(T, 1);
+ T->sign = y->sign ^ x->sign;
+ } else if (y->expn == BF_EXP_ZERO && x->expn == BF_EXP_ZERO) {
+ bf_set_zero(T, y->sign ^ x->sign);
+ } else {
+ bf_div(T, y, x, prec1, BF_RNDF);
+ }
+ ret = bf_atan(r, T, prec1, BF_RNDF);
+
+ if (x->sign) {
+ /* if x < 0 (it includes -0), return sign(y)*pi + atan(y/x) */
+ bf_const_pi(T, prec1, BF_RNDF);
+ T->sign = y->sign;
+ bf_add(r, r, T, prec1, BF_RNDN);
+ ret |= BF_ST_INEXACT;
+ }
+
+ bf_delete(T);
+ return ret;
+}
+
+int bf_atan2(bf_t *r, const bf_t *y, const bf_t *x,
+ limb_t prec, bf_flags_t flags)
+{
+ return bf_ziv_rounding(r, y, prec, flags, bf_atan2_internal, (void *)x);
+}
+
+static int bf_asin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)
+{
+ bf_context_t *s = r->ctx;
+ BOOL is_acos = (BOOL)(intptr_t)opaque;
+ bf_t T_s, *T = &T_s;
+ limb_t prec1, prec2;
+
+ /* asin(x) = atan(x/sqrt(1-x^2))
+ acos(x) = pi/2 - asin(x) */
+ prec1 = prec + 8;
+ /* increase the precision in x^2 to compensate the cancellation in
+ (1-x^2) if x is close to 1 */
+ /* XXX: use less precision when possible */
+ if (a->expn >= 0)
+ prec2 = BF_PREC_INF;
+ else
+ prec2 = prec1;
+ bf_init(s, T);
+ bf_mul(T, a, a, prec2, BF_RNDN);
+ bf_neg(T);
+ bf_add_si(T, T, 1, prec2, BF_RNDN);
+
+ bf_sqrt(r, T, prec1, BF_RNDN);
+ bf_div(T, a, r, prec1, BF_RNDN);
+ if (is_acos)
+ bf_neg(T);
+ bf_atan_internal(r, T, prec1, (void *)(intptr_t)is_acos);
+ bf_delete(T);
+ return BF_ST_INEXACT;
+}
+
+int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
+{
+ bf_context_t *s = r->ctx;
+ bf_t T_s, *T = &T_s;
+ int res;
+
+ if (a->len == 0) {
+ if (a->expn == BF_EXP_NAN) {
+ bf_set_nan(r);
+ return 0;
+ } else if (a->expn == BF_EXP_INF) {
+ bf_set_nan(r);
+ return BF_ST_INVALID_OP;
+ } else {
+ bf_set_zero(r, a->sign);
+ return 0;
+ }
+ }
+ bf_init(s, T);
+ bf_set_ui(T, 1);
+ res = bf_cmpu(a, T);
+ bf_delete(T);
+ if (res > 0) {
+ bf_set_nan(r);
+ return BF_ST_INVALID_OP;
+ }
+
+ /* small argument case: result = x+r(x) with r(x) = x^3/6 +
+ O(X^5). We assume r(x) < 2^(3*EXP(x) - 2). */
+ if (a->expn < 0) {
+ slimb_t e;
+ e = sat_add(2 * a->expn, a->expn - 2);
+ if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {
+ bf_set(r, a);
+ return bf_add_epsilon(r, r, e, a->sign, prec, flags);
+ }
+ }
+
+ return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)FALSE);
+}
+
+int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
+{
+ bf_context_t *s = r->ctx;
+ bf_t T_s, *T = &T_s;
+ int res;
+
+ if (a->len == 0) {
+ if (a->expn == BF_EXP_NAN) {
+ bf_set_nan(r);
+ return 0;
+ } else if (a->expn == BF_EXP_INF) {
+ bf_set_nan(r);
+ return BF_ST_INVALID_OP;
+ } else {
+ bf_const_pi(r, prec, flags);
+ bf_mul_2exp(r, -1, BF_PREC_INF, BF_RNDZ);
+ return BF_ST_INEXACT;
+ }
+ }
+ bf_init(s, T);
+ bf_set_ui(T, 1);
+ res = bf_cmpu(a, T);
+ bf_delete(T);
+ if (res > 0) {
+ bf_set_nan(r);
+ return BF_ST_INVALID_OP;
+ } else if (res == 0 && a->sign == 0) {
+ bf_set_zero(r, 0);
+ return 0;
+ }
+
+ return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)TRUE);
+}
+
+/***************************************************************/
+/* decimal floating point numbers */
+
+#ifdef USE_BF_DEC
+
+#define adddq(r1, r0, a1, a0) \
+ do { \
+ limb_t __t = r0; \
+ r0 += (a0); \
+ r1 += (a1) + (r0 < __t); \
+ } while (0)
+
+#define subdq(r1, r0, a1, a0) \
+ do { \
+ limb_t __t = r0; \
+ r0 -= (a0); \
+ r1 -= (a1) + (r0 > __t); \
+ } while (0)
+
+#if LIMB_BITS == 64
+
+/* Note: we assume __int128 is available */
+#define muldq(r1, r0, a, b) \
+ do { \
+ unsigned __int128 __t; \
+ __t = (unsigned __int128)(a) * (unsigned __int128)(b); \
+ r0 = __t; \
+ r1 = __t >> 64; \
+ } while (0)
+
+#define divdq(q, r, a1, a0, b) \
+ do { \
+ unsigned __int128 __t; \
+ limb_t __b = (b); \
+ __t = ((unsigned __int128)(a1) << 64) | (a0); \
+ q = __t / __b; \
+ r = __t % __b; \
+ } while (0)
+
+#else
+
+#define muldq(r1, r0, a, b) \
+ do { \
+ uint64_t __t; \
+ __t = (uint64_t)(a) * (uint64_t)(b); \
+ r0 = __t; \
+ r1 = __t >> 32; \
+ } while (0)
+
+#define divdq(q, r, a1, a0, b) \
+ do { \
+ uint64_t __t; \
+ limb_t __b = (b); \
+ __t = ((uint64_t)(a1) << 32) | (a0); \
+ q = __t / __b; \
+ r = __t % __b; \
+ } while (0)
+
+#endif /* LIMB_BITS != 64 */
+
+#if LIMB_DIGITS == 19
+
+/* WARNING: hardcoded for b = 1e19. It is assumed that:
+ 0 <= a1 < 2^63 */
+#define divdq_base(q, r, a1, a0)\
+do {\
+ uint64_t __a0, __a1, __t0, __t1, __b = BF_DEC_BASE; \
+ __a0 = a0;\
+ __a1 = a1;\
+ __t0 = __a1;\
+ __t0 = shld(__t0, __a0, 1);\
+ muldq(q, __t1, __t0, UINT64_C(17014118346046923173)); \
+ muldq(__t1, __t0, q, __b);\
+ subdq(__a1, __a0, __t1, __t0);\
+ subdq(__a1, __a0, 1, __b * 2); \
+ __t0 = (slimb_t)__a1 >> 1; \
+ q += 2 + __t0;\
+ adddq(__a1, __a0, 0, __b & __t0);\
+ q += __a1; \
+ __a0 += __b & __a1; \
+ r = __a0;\
+} while(0)
+
+#elif LIMB_DIGITS == 9
+
+/* WARNING: hardcoded for b = 1e9. It is assumed that:
+ 0 <= a1 < 2^29 */
+#define divdq_base(q, r, a1, a0)\
+do {\
+ uint32_t __t0, __t1, __b = BF_DEC_BASE; \
+ __t0 = a1;\
+ __t1 = a0;\
+ __t0 = (__t0 << 3) | (__t1 >> (32 - 3)); \
+ muldq(q, __t1, __t0, 2305843009U);\
+ r = a0 - q * __b;\
+ __t1 = (r >= __b);\
+ q += __t1;\
+ if (__t1)\
+ r -= __b;\
+} while(0)
+
+#endif
+
+/* fast integer division by a fixed constant */
+
+typedef struct FastDivData {
+ limb_t m1; /* multiplier */
+ int8_t shift1;
+ int8_t shift2;
+} FastDivData;
+
+/* From "Division by Invariant Integers using Multiplication" by
+ Torborn Granlund and Peter L. Montgomery */
+/* d must be != 0 */
+static inline __maybe_unused void fast_udiv_init(FastDivData *s, limb_t d)
+{
+ int l;
+ limb_t q, r, m1;
+ if (d == 1)
+ l = 0;
+ else
+ l = 64 - clz64(d - 1);
+ divdq(q, r, ((limb_t)1 << l) - d, 0, d);
+ (void)r;
+ m1 = q + 1;
+ // printf("d=%lu l=%d m1=0x%016lx\n", d, l, m1);
+ s->m1 = m1;
+ s->shift1 = l;
+ if (s->shift1 > 1)
+ s->shift1 = 1;
+ s->shift2 = l - 1;
+ if (s->shift2 < 0)
+ s->shift2 = 0;
+}
+
+static inline limb_t fast_udiv(limb_t a, const FastDivData *s)
+{
+ limb_t t0, t1;
+ muldq(t1, t0, s->m1, a);
+ t0 = (a - t1) >> s->shift1;
+ return (t1 + t0) >> s->shift2;
+}
+
+#endif // USE_BF_DEC
+/* contains 10^i */
+const limb_t mp_pow_dec[LIMB_DIGITS + 1] = {
+ 1U,
+ 10U,
+ 100U,
+ 1000U,
+ 10000U,
+ 100000U,
+ 1000000U,
+ 10000000U,
+ 100000000U,
+ 1000000000U,
+#if LIMB_BITS == 64
+ 10000000000U,
+ 100000000000U,
+ 1000000000000U,
+ 10000000000000U,
+ 100000000000000U,
+ 1000000000000000U,
+ 10000000000000000U,
+ 100000000000000000U,
+ 1000000000000000000U,
+ 10000000000000000000U,
+#endif
+};
+#ifdef USE_BF_DEC
+
+/* precomputed from fast_udiv_init(10^i) */
+static const FastDivData mp_pow_div[LIMB_DIGITS + 1] = {
+#if LIMB_BITS == 32
+ { 0x00000001, 0, 0 },
+ { 0x9999999a, 1, 3 },
+ { 0x47ae147b, 1, 6 },
+ { 0x0624dd30, 1, 9 },
+ { 0xa36e2eb2, 1, 13 },
+ { 0x4f8b588f, 1, 16 },
+ { 0x0c6f7a0c, 1, 19 },
+ { 0xad7f29ac, 1, 23 },
+ { 0x5798ee24, 1, 26 },
+ { 0x12e0be83, 1, 29 },
+#else
+ { 0x0000000000000001, 0, 0 },
+ { 0x999999999999999a, 1, 3 },
+ { 0x47ae147ae147ae15, 1, 6 },
+ { 0x0624dd2f1a9fbe77, 1, 9 },
+ { 0xa36e2eb1c432ca58, 1, 13 },
+ { 0x4f8b588e368f0847, 1, 16 },
+ { 0x0c6f7a0b5ed8d36c, 1, 19 },
+ { 0xad7f29abcaf48579, 1, 23 },
+ { 0x5798ee2308c39dfa, 1, 26 },
+ { 0x12e0be826d694b2f, 1, 29 },
+ { 0xb7cdfd9d7bdbab7e, 1, 33 },
+ { 0x5fd7fe17964955fe, 1, 36 },
+ { 0x19799812dea11198, 1, 39 },
+ { 0xc25c268497681c27, 1, 43 },
+ { 0x6849b86a12b9b01f, 1, 46 },
+ { 0x203af9ee756159b3, 1, 49 },
+ { 0xcd2b297d889bc2b7, 1, 53 },
+ { 0x70ef54646d496893, 1, 56 },
+ { 0x2725dd1d243aba0f, 1, 59 },
+ { 0xd83c94fb6d2ac34d, 1, 63 },
+#endif
+};
+
+/* divide by 10^shift with 0 <= shift <= LIMB_DIGITS */
+static inline limb_t fast_shr_dec(limb_t a, int shift)
+{
+ return fast_udiv(a, &mp_pow_div[shift]);
+}
+
+/* division and remainder by 10^shift */
+#define fast_shr_rem_dec(q, r, a, shift) q = fast_shr_dec(a, shift), r = a - q * mp_pow_dec[shift]
+
+limb_t mp_add_dec(limb_t *res, const limb_t *op1, const limb_t *op2,
+ mp_size_t n, limb_t carry)
+{
+ limb_t base = BF_DEC_BASE;
+ mp_size_t i;
+ limb_t k, a, v;
+
+ k=carry;
+ for(i=0;i<n;i++) {
+ /* XXX: reuse the trick in add_mod */
+ v = op1[i];
+ a = v + op2[i] + k - base;
+ k = a <= v;
+ if (!k)
+ a += base;
+ res[i]=a;
+ }
+ return k;
+}
+
+limb_t mp_add_ui_dec(limb_t *tab, limb_t b, mp_size_t n)
+{
+ limb_t base = BF_DEC_BASE;
+ mp_size_t i;
+ limb_t k, a, v;
+
+ k=b;
+ for(i=0;i<n;i++) {
+ v = tab[i];
+ a = v + k - base;
+ k = a <= v;
+ if (!k)
+ a += base;
+ tab[i] = a;
+ if (k == 0)
+ break;
+ }
+ return k;
+}
+
+limb_t mp_sub_dec(limb_t *res, const limb_t *op1, const limb_t *op2,
+ mp_size_t n, limb_t carry)
+{
+ limb_t base = BF_DEC_BASE;
+ mp_size_t i;
+ limb_t k, v, a;
+
+ k=carry;
+ for(i=0;i<n;i++) {
+ v = op1[i];
+ a = v - op2[i] - k;
+ k = a > v;
+ if (k)
+ a += base;
+ res[i] = a;
+ }
+ return k;
+}
+
+limb_t mp_sub_ui_dec(limb_t *tab, limb_t b, mp_size_t n)
+{
+ limb_t base = BF_DEC_BASE;
+ mp_size_t i;
+ limb_t k, v, a;
+
+ k=b;
+ for(i=0;i<n;i++) {
+ v = tab[i];
+ a = v - k;
+ k = a > v;
+ if (k)
+ a += base;
+ tab[i]=a;
+ if (k == 0)
+ break;
+ }
+ return k;
+}
+
+/* taba[] = taba[] * b + l. 0 <= b, l <= base - 1. Return the high carry */
+limb_t mp_mul1_dec(limb_t *tabr, const limb_t *taba, mp_size_t n,
+ limb_t b, limb_t l)
+{
+ mp_size_t i;
+ limb_t t0, t1, r;
+
+ for(i = 0; i < n; i++) {
+ muldq(t1, t0, taba[i], b);
+ adddq(t1, t0, 0, l);
+ divdq_base(l, r, t1, t0);
+ tabr[i] = r;
+ }
+ return l;
+}
+
+/* tabr[] += taba[] * b. 0 <= b <= base - 1. Return the value to add
+ to the high word */
+limb_t mp_add_mul1_dec(limb_t *tabr, const limb_t *taba, mp_size_t n,
+ limb_t b)
+{
+ mp_size_t i;
+ limb_t l, t0, t1, r;
+
+ l = 0;
+ for(i = 0; i < n; i++) {
+ muldq(t1, t0, taba[i], b);
+ adddq(t1, t0, 0, l);
+ adddq(t1, t0, 0, tabr[i]);
+ divdq_base(l, r, t1, t0);
+ tabr[i] = r;
+ }
+ return l;
+}
+
+/* tabr[] -= taba[] * b. 0 <= b <= base - 1. Return the value to
+ substract to the high word. */
+limb_t mp_sub_mul1_dec(limb_t *tabr, const limb_t *taba, mp_size_t n,
+ limb_t b)
+{
+ limb_t base = BF_DEC_BASE;
+ mp_size_t i;
+ limb_t l, t0, t1, r, a, v, c;
+
+ /* XXX: optimize */
+ l = 0;
+ for(i = 0; i < n; i++) {
+ muldq(t1, t0, taba[i], b);
+ adddq(t1, t0, 0, l);
+ divdq_base(l, r, t1, t0);
+ v = tabr[i];
+ a = v - r;
+ c = a > v;
+ if (c)
+ a += base;
+ /* never bigger than base because r = 0 when l = base - 1 */
+ l += c;
+ tabr[i] = a;
+ }
+ return l;
+}
+
+/* size of the result : op1_size + op2_size. */
+void mp_mul_basecase_dec(limb_t *result,
+ const limb_t *op1, mp_size_t op1_size,
+ const limb_t *op2, mp_size_t op2_size)
+{
+ mp_size_t i;
+ limb_t r;
+
+ result[op1_size] = mp_mul1_dec(result, op1, op1_size, op2[0], 0);
+
+ for(i=1;i<op2_size;i++) {
+ r = mp_add_mul1_dec(result + i, op1, op1_size, op2[i]);
+ result[i + op1_size] = r;
+ }
+}
+
+/* taba[] = (taba[] + r*base^na) / b. 0 <= b < base. 0 <= r <
+ b. Return the remainder. */
+limb_t mp_div1_dec(limb_t *tabr, const limb_t *taba, mp_size_t na,
+ limb_t b, limb_t r)
+{
+ limb_t base = BF_DEC_BASE;
+ mp_size_t i;
+ limb_t t0, t1, q;
+ int shift;
+
+#if (BF_DEC_BASE % 2) == 0
+ if (b == 2) {
+ limb_t base_div2;
+ /* Note: only works if base is even */
+ base_div2 = base >> 1;
+ if (r)
+ r = base_div2;
+ for(i = na - 1; i >= 0; i--) {
+ t0 = taba[i];
+ tabr[i] = (t0 >> 1) + r;
+ r = 0;
+ if (t0 & 1)
+ r = base_div2;
+ }
+ if (r)
+ r = 1;
+ } else
+#endif
+ if (na >= UDIV1NORM_THRESHOLD) {
+ shift = clz(b);
+ if (shift == 0) {
+ /* normalized case: b >= 2^(LIMB_BITS-1) */
+ limb_t b_inv;
+ b_inv = udiv1norm_init(b);
+ for(i = na - 1; i >= 0; i--) {
+ muldq(t1, t0, r, base);
+ adddq(t1, t0, 0, taba[i]);
+ q = udiv1norm(&r, t1, t0, b, b_inv);
+ tabr[i] = q;
+ }
+ } else {
+ limb_t b_inv;
+ b <<= shift;
+ b_inv = udiv1norm_init(b);
+ for(i = na - 1; i >= 0; i--) {
+ muldq(t1, t0, r, base);
+ adddq(t1, t0, 0, taba[i]);
+ t1 = (t1 << shift) | (t0 >> (LIMB_BITS - shift));
+ t0 <<= shift;
+ q = udiv1norm(&r, t1, t0, b, b_inv);
+ r >>= shift;
+ tabr[i] = q;
+ }
+ }
+ } else {
+ for(i = na - 1; i >= 0; i--) {
+ muldq(t1, t0, r, base);
+ adddq(t1, t0, 0, taba[i]);
+ divdq(q, r, t1, t0, b);
+ tabr[i] = q;
+ }
+ }
+ return r;
+}
+
+static __maybe_unused void mp_print_str_dec(const char *str,
+ const limb_t *tab, slimb_t n)
+{
+ slimb_t i;
+ printf("%s=", str);
+ for(i = n - 1; i >= 0; i--) {
+ if (i != n - 1)
+ printf("_");
+ printf("%0*" PRIu_LIMB, LIMB_DIGITS, tab[i]);
+ }
+ printf("\n");
+}
+
+static __maybe_unused void mp_print_str_h_dec(const char *str,
+ const limb_t *tab, slimb_t n,
+ limb_t high)
+{
+ slimb_t i;
+ printf("%s=", str);
+ printf("%0*" PRIu_LIMB, LIMB_DIGITS, high);
+ for(i = n - 1; i >= 0; i--) {
+ printf("_");
+ printf("%0*" PRIu_LIMB, LIMB_DIGITS, tab[i]);
+ }
+ printf("\n");
+}
+
+//#define DEBUG_DIV_SLOW
+
+#define DIV_STATIC_ALLOC_LEN 16
+
+/* return q = a / b and r = a % b.
+
+ taba[na] must be allocated if tabb1[nb - 1] < B / 2. tabb1[nb - 1]
+ must be != zero. na must be >= nb. 's' can be NULL if tabb1[nb - 1]
+ >= B / 2.
+
+ The remainder is is returned in taba and contains nb libms. tabq
+ contains na - nb + 1 limbs. No overlap is permitted.
+
+ Running time of the standard method: (na - nb + 1) * nb
+ Return 0 if OK, -1 if memory alloc error
+*/
+/* XXX: optimize */
+static int mp_div_dec(bf_context_t *s, limb_t *tabq,
+ limb_t *taba, mp_size_t na,
+ const limb_t *tabb1, mp_size_t nb)
+{
+ limb_t base = BF_DEC_BASE;
+ limb_t r, mult, t0, t1, a, c, q, v, *tabb;
+ mp_size_t i, j;
+ limb_t static_tabb[DIV_STATIC_ALLOC_LEN];
+
+#ifdef DEBUG_DIV_SLOW
+ mp_print_str_dec("a", taba, na);
+ mp_print_str_dec("b", tabb1, nb);
+#endif
+
+ /* normalize tabb */
+ r = tabb1[nb - 1];
+ assert(r != 0);
+ i = na - nb;
+ if (r >= BF_DEC_BASE / 2) {
+ mult = 1;
+ tabb = (limb_t *)tabb1;
+ q = 1;
+ for(j = nb - 1; j >= 0; j--) {
+ if (taba[i + j] != tabb[j]) {
+ if (taba[i + j] < tabb[j])
+ q = 0;
+ break;
+ }
+ }
+ tabq[i] = q;
+ if (q) {
+ mp_sub_dec(taba + i, taba + i, tabb, nb, 0);
+ }
+ i--;
+ } else {
+ mult = base / (r + 1);
+ if (likely(nb <= DIV_STATIC_ALLOC_LEN)) {
+ tabb = static_tabb;
+ } else {
+ tabb = bf_malloc(s, sizeof(limb_t) * nb);
+ if (!tabb)
+ return -1;
+ }
+ mp_mul1_dec(tabb, tabb1, nb, mult, 0);
+ taba[na] = mp_mul1_dec(taba, taba, na, mult, 0);
+ }
+
+#ifdef DEBUG_DIV_SLOW
+ printf("mult=" FMT_LIMB "\n", mult);
+ mp_print_str_dec("a_norm", taba, na + 1);
+ mp_print_str_dec("b_norm", tabb, nb);
+#endif
+
+ for(; i >= 0; i--) {
+ if (unlikely(taba[i + nb] >= tabb[nb - 1])) {
+ /* XXX: check if it is really possible */
+ q = base - 1;
+ } else {
+ muldq(t1, t0, taba[i + nb], base);
+ adddq(t1, t0, 0, taba[i + nb - 1]);
+ divdq(q, r, t1, t0, tabb[nb - 1]);
+ }
+ // printf("i=%d q1=%ld\n", i, q);
+
+ r = mp_sub_mul1_dec(taba + i, tabb, nb, q);
+ // mp_dump("r1", taba + i, nb, bd);
+ // printf("r2=%ld\n", r);
+
+ v = taba[i + nb];
+ a = v - r;
+ c = a > v;
+ if (c)
+ a += base;
+ taba[i + nb] = a;
+
+ if (c != 0) {
+ /* negative result */
+ for(;;) {
+ q--;
+ c = mp_add_dec(taba + i, taba + i, tabb, nb, 0);
+ /* propagate carry and test if positive result */
+ if (c != 0) {
+ if (++taba[i + nb] == base) {
+ break;
+ }
+ }
+ }
+ }
+ tabq[i] = q;
+ }
+
+#ifdef DEBUG_DIV_SLOW
+ mp_print_str_dec("q", tabq, na - nb + 1);
+ mp_print_str_dec("r", taba, nb);
+#endif
+
+ /* remove the normalization */
+ if (mult != 1) {
+ mp_div1_dec(taba, taba, nb, mult, 0);
+ if (unlikely(tabb != static_tabb))
+ bf_free(s, tabb);
+ }
+ return 0;
+}
+
+/* divide by 10^shift */
+static limb_t mp_shr_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n,
+ limb_t shift, limb_t high)
+{
+ mp_size_t i;
+ limb_t l, a, q, r;
+
+ assert(shift >= 1 && shift < LIMB_DIGITS);
+ l = high;
+ for(i = n - 1; i >= 0; i--) {
+ a = tab[i];
+ fast_shr_rem_dec(q, r, a, shift);
+ tab_r[i] = q + l * mp_pow_dec[LIMB_DIGITS - shift];
+ l = r;
+ }
+ return l;
+}
+
+/* multiply by 10^shift */
+static limb_t mp_shl_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n,
+ limb_t shift, limb_t low)
+{
+ mp_size_t i;
+ limb_t l, a, q, r;
+
+ assert(shift >= 1 && shift < LIMB_DIGITS);
+ l = low;
+ for(i = 0; i < n; i++) {
+ a = tab[i];
+ fast_shr_rem_dec(q, r, a, LIMB_DIGITS - shift);
+ tab_r[i] = r * mp_pow_dec[shift] + l;
+ l = q;
+ }
+ return l;
+}
+
+static limb_t mp_sqrtrem2_dec(limb_t *tabs, limb_t *taba)
+{
+ int k;
+ dlimb_t a, b, r;
+ limb_t taba1[2], s, r0, r1;
+
+ /* convert to binary and normalize */
+ a = (dlimb_t)taba[1] * BF_DEC_BASE + taba[0];
+ k = clz(a >> LIMB_BITS) & ~1;
+ b = a << k;
+ taba1[0] = b;
+ taba1[1] = b >> LIMB_BITS;
+ mp_sqrtrem2(&s, taba1);
+ s >>= (k >> 1);
+ /* convert the remainder back to decimal */
+ r = a - (dlimb_t)s * (dlimb_t)s;
+ divdq_base(r1, r0, r >> LIMB_BITS, r);
+ taba[0] = r0;
+ tabs[0] = s;
+ return r1;
+}
+
+//#define DEBUG_SQRTREM_DEC
+
+/* tmp_buf must contain (n / 2 + 1 limbs) */
+static limb_t mp_sqrtrem_rec_dec(limb_t *tabs, limb_t *taba, limb_t n,
+ limb_t *tmp_buf)
+{
+ limb_t l, h, rh, ql, qh, c, i;
+
+ if (n == 1)
+ return mp_sqrtrem2_dec(tabs, taba);
+#ifdef DEBUG_SQRTREM_DEC
+ mp_print_str_dec("a", taba, 2 * n);
+#endif
+ l = n / 2;
+ h = n - l;
+ qh = mp_sqrtrem_rec_dec(tabs + l, taba + 2 * l, h, tmp_buf);
+#ifdef DEBUG_SQRTREM_DEC
+ mp_print_str_dec("s1", tabs + l, h);
+ mp_print_str_h_dec("r1", taba + 2 * l, h, qh);
+ mp_print_str_h_dec("r2", taba + l, n, qh);
+#endif
+
+ /* the remainder is in taba + 2 * l. Its high bit is in qh */
+ if (qh) {
+ mp_sub_dec(taba + 2 * l, taba + 2 * l, tabs + l, h, 0);
+ }
+ /* instead of dividing by 2*s, divide by s (which is normalized)
+ and update q and r */
+ mp_div_dec(NULL, tmp_buf, taba + l, n, tabs + l, h);
+ qh += tmp_buf[l];
+ for(i = 0; i < l; i++)
+ tabs[i] = tmp_buf[i];
+ ql = mp_div1_dec(tabs, tabs, l, 2, qh & 1);
+ qh = qh >> 1; /* 0 or 1 */
+ if (ql)
+ rh = mp_add_dec(taba + l, taba + l, tabs + l, h, 0);
+ else
+ rh = 0;
+#ifdef DEBUG_SQRTREM_DEC
+ mp_print_str_h_dec("q", tabs, l, qh);
+ mp_print_str_h_dec("u", taba + l, h, rh);
+#endif
+
+ mp_add_ui_dec(tabs + l, qh, h);
+#ifdef DEBUG_SQRTREM_DEC
+ mp_print_str_dec("s2", tabs, n);
+#endif
+
+ /* q = qh, tabs[l - 1 ... 0], r = taba[n - 1 ... l] */
+ /* subtract q^2. if qh = 1 then q = B^l, so we can take shortcuts */
+ if (qh) {
+ c = qh;
+ } else {
+ mp_mul_basecase_dec(taba + n, tabs, l, tabs, l);
+ c = mp_sub_dec(taba, taba, taba + n, 2 * l, 0);
+ }
+ rh -= mp_sub_ui_dec(taba + 2 * l, c, n - 2 * l);
+ if ((slimb_t)rh < 0) {
+ mp_sub_ui_dec(tabs, 1, n);
+ rh += mp_add_mul1_dec(taba, tabs, n, 2);
+ rh += mp_add_ui_dec(taba, 1, n);
+ }
+ return rh;
+}
+
+/* 'taba' has 2*n limbs with n >= 1 and taba[2*n-1] >= B/4. Return (s,
+ r) with s=floor(sqrt(a)) and r=a-s^2. 0 <= r <= 2 * s. tabs has n
+ limbs. r is returned in the lower n limbs of taba. Its r[n] is the
+ returned value of the function. */
+int mp_sqrtrem_dec(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n)
+{
+ limb_t tmp_buf1[8];
+ limb_t *tmp_buf;
+ mp_size_t n2;
+ n2 = n / 2 + 1;
+ if (n2 <= countof(tmp_buf1)) {
+ tmp_buf = tmp_buf1;
+ } else {
+ tmp_buf = bf_malloc(s, sizeof(limb_t) * n2);
+ if (!tmp_buf)
+ return -1;
+ }
+ taba[n] = mp_sqrtrem_rec_dec(tabs, taba, n, tmp_buf);
+ if (tmp_buf != tmp_buf1)
+ bf_free(s, tmp_buf);
+ return 0;
+}
+
+/* return the number of leading zero digits, from 0 to LIMB_DIGITS */
+static int clz_dec(limb_t a)
+{
+ if (a == 0)
+ return LIMB_DIGITS;
+ switch(LIMB_BITS - 1 - clz(a)) {
+ case 0: /* 1-1 */
+ return LIMB_DIGITS - 1;
+ case 1: /* 2-3 */
+ return LIMB_DIGITS - 1;
+ case 2: /* 4-7 */
+ return LIMB_DIGITS - 1;
+ case 3: /* 8-15 */
+ if (a < 10)
+ return LIMB_DIGITS - 1;
+ else
+ return LIMB_DIGITS - 2;
+ case 4: /* 16-31 */
+ return LIMB_DIGITS - 2;
+ case 5: /* 32-63 */
+ return LIMB_DIGITS - 2;
+ case 6: /* 64-127 */
+ if (a < 100)
+ return LIMB_DIGITS - 2;
+ else
+ return LIMB_DIGITS - 3;
+ case 7: /* 128-255 */
+ return LIMB_DIGITS - 3;
+ case 8: /* 256-511 */
+ return LIMB_DIGITS - 3;
+ case 9: /* 512-1023 */
+ if (a < 1000)
+ return LIMB_DIGITS - 3;
+ else
+ return LIMB_DIGITS - 4;
+ case 10: /* 1024-2047 */
+ return LIMB_DIGITS - 4;
+ case 11: /* 2048-4095 */
+ return LIMB_DIGITS - 4;
+ case 12: /* 4096-8191 */
+ return LIMB_DIGITS - 4;
+ case 13: /* 8192-16383 */
+ if (a < 10000)
+ return LIMB_DIGITS - 4;
+ else
+ return LIMB_DIGITS - 5;
+ case 14: /* 16384-32767 */
+ return LIMB_DIGITS - 5;
+ case 15: /* 32768-65535 */
+ return LIMB_DIGITS - 5;
+ case 16: /* 65536-131071 */
+ if (a < 100000)
+ return LIMB_DIGITS - 5;
+ else
+ return LIMB_DIGITS - 6;
+ case 17: /* 131072-262143 */
+ return LIMB_DIGITS - 6;
+ case 18: /* 262144-524287 */
+ return LIMB_DIGITS - 6;
+ case 19: /* 524288-1048575 */
+ if (a < 1000000)
+ return LIMB_DIGITS - 6;
+ else
+ return LIMB_DIGITS - 7;
+ case 20: /* 1048576-2097151 */
+ return LIMB_DIGITS - 7;
+ case 21: /* 2097152-4194303 */
+ return LIMB_DIGITS - 7;
+ case 22: /* 4194304-8388607 */
+ return LIMB_DIGITS - 7;
+ case 23: /* 8388608-16777215 */
+ if (a < 10000000)
+ return LIMB_DIGITS - 7;
+ else
+ return LIMB_DIGITS - 8;
+ case 24: /* 16777216-33554431 */
+ return LIMB_DIGITS - 8;
+ case 25: /* 33554432-67108863 */
+ return LIMB_DIGITS - 8;
+ case 26: /* 67108864-134217727 */
+ if (a < 100000000)
+ return LIMB_DIGITS - 8;
+ else
+ return LIMB_DIGITS - 9;
+#if LIMB_BITS == 64
+ case 27: /* 134217728-268435455 */
+ return LIMB_DIGITS - 9;
+ case 28: /* 268435456-536870911 */
+ return LIMB_DIGITS - 9;
+ case 29: /* 536870912-1073741823 */
+ if (a < 1000000000)
+ return LIMB_DIGITS - 9;
+ else
+ return LIMB_DIGITS - 10;
+ case 30: /* 1073741824-2147483647 */
+ return LIMB_DIGITS - 10;
+ case 31: /* 2147483648-4294967295 */
+ return LIMB_DIGITS - 10;
+ case 32: /* 4294967296-8589934591 */
+ return LIMB_DIGITS - 10;
+ case 33: /* 8589934592-17179869183 */
+ if (a < 10000000000)
+ return LIMB_DIGITS - 10;
+ else
+ return LIMB_DIGITS - 11;
+ case 34: /* 17179869184-34359738367 */
+ return LIMB_DIGITS - 11;
+ case 35: /* 34359738368-68719476735 */
+ return LIMB_DIGITS - 11;
+ case 36: /* 68719476736-137438953471 */
+ if (a < 100000000000)
+ return LIMB_DIGITS - 11;
+ else
+ return LIMB_DIGITS - 12;
+ case 37: /* 137438953472-274877906943 */
+ return LIMB_DIGITS - 12;
+ case 38: /* 274877906944-549755813887 */
+ return LIMB_DIGITS - 12;
+ case 39: /* 549755813888-1099511627775 */
+ if (a < 1000000000000)
+ return LIMB_DIGITS - 12;
+ else
+ return LIMB_DIGITS - 13;
+ case 40: /* 1099511627776-2199023255551 */
+ return LIMB_DIGITS - 13;
+ case 41: /* 2199023255552-4398046511103 */
+ return LIMB_DIGITS - 13;
+ case 42: /* 4398046511104-8796093022207 */
+ return LIMB_DIGITS - 13;
+ case 43: /* 8796093022208-17592186044415 */
+ if (a < 10000000000000)
+ return LIMB_DIGITS - 13;
+ else
+ return LIMB_DIGITS - 14;
+ case 44: /* 17592186044416-35184372088831 */
+ return LIMB_DIGITS - 14;
+ case 45: /* 35184372088832-70368744177663 */
+ return LIMB_DIGITS - 14;
+ case 46: /* 70368744177664-140737488355327 */
+ if (a < 100000000000000)
+ return LIMB_DIGITS - 14;
+ else
+ return LIMB_DIGITS - 15;
+ case 47: /* 140737488355328-281474976710655 */
+ return LIMB_DIGITS - 15;
+ case 48: /* 281474976710656-562949953421311 */
+ return LIMB_DIGITS - 15;
+ case 49: /* 562949953421312-1125899906842623 */
+ if (a < 1000000000000000)
+ return LIMB_DIGITS - 15;
+ else
+ return LIMB_DIGITS - 16;
+ case 50: /* 1125899906842624-2251799813685247 */
+ return LIMB_DIGITS - 16;
+ case 51: /* 2251799813685248-4503599627370495 */
+ return LIMB_DIGITS - 16;
+ case 52: /* 4503599627370496-9007199254740991 */
+ return LIMB_DIGITS - 16;
+ case 53: /* 9007199254740992-18014398509481983 */
+ if (a < 10000000000000000)
+ return LIMB_DIGITS - 16;
+ else
+ return LIMB_DIGITS - 17;
+ case 54: /* 18014398509481984-36028797018963967 */
+ return LIMB_DIGITS - 17;
+ case 55: /* 36028797018963968-72057594037927935 */
+ return LIMB_DIGITS - 17;
+ case 56: /* 72057594037927936-144115188075855871 */
+ if (a < 100000000000000000)
+ return LIMB_DIGITS - 17;
+ else
+ return LIMB_DIGITS - 18;
+ case 57: /* 144115188075855872-288230376151711743 */
+ return LIMB_DIGITS - 18;
+ case 58: /* 288230376151711744-576460752303423487 */
+ return LIMB_DIGITS - 18;
+ case 59: /* 576460752303423488-1152921504606846975 */
+ if (a < 1000000000000000000)
+ return LIMB_DIGITS - 18;
+ else
+ return LIMB_DIGITS - 19;
+#endif
+ default:
+ return 0;
+ }
+}
+
+/* for debugging */
+void bfdec_print_str(const char *str, const bfdec_t *a)
+{
+ slimb_t i;
+ printf("%s=", str);
+
+ if (a->expn == BF_EXP_NAN) {
+ printf("NaN");
+ } else {
+ if (a->sign)
+ putchar('-');
+ if (a->expn == BF_EXP_ZERO) {
+ putchar('0');
+ } else if (a->expn == BF_EXP_INF) {
+ printf("Inf");
+ } else {
+ printf("0.");
+ for(i = a->len - 1; i >= 0; i--)
+ printf("%0*" PRIu_LIMB, LIMB_DIGITS, a->tab[i]);
+ printf("e%" PRId_LIMB, a->expn);
+ }
+ }
+ printf("\n");
+}
+
+/* return != 0 if one digit between 0 and bit_pos inclusive is not zero. */
+static inline limb_t scan_digit_nz(const bfdec_t *r, slimb_t bit_pos)
+{
+ slimb_t pos;
+ limb_t v, q;
+ int shift;
+
+ if (bit_pos < 0)
+ return 0;
+ pos = (limb_t)bit_pos / LIMB_DIGITS;
+ shift = (limb_t)bit_pos % LIMB_DIGITS;
+ fast_shr_rem_dec(q, v, r->tab[pos], shift + 1);
+ (void)q;
+ if (v != 0)
+ return 1;
+ pos--;
+ while (pos >= 0) {
+ if (r->tab[pos] != 0)
+ return 1;
+ pos--;
+ }
+ return 0;
+}
+
+static limb_t get_digit(const limb_t *tab, limb_t len, slimb_t pos)
+{
+ slimb_t i;
+ int shift;
+ i = floor_div(pos, LIMB_DIGITS);
+ if (i < 0 || i >= len)
+ return 0;
+ shift = pos - i * LIMB_DIGITS;
+ return fast_shr_dec(tab[i], shift) % 10;
+}
+
+#if 0
+static limb_t get_digits(const limb_t *tab, limb_t len, slimb_t pos)
+{
+ limb_t a0, a1;
+ int shift;
+ slimb_t i;
+
+ i = floor_div(pos, LIMB_DIGITS);
+ shift = pos - i * LIMB_DIGITS;
+ if (i >= 0 && i < len)
+ a0 = tab[i];
+ else
+ a0 = 0;
+ if (shift == 0) {
+ return a0;
+ } else {
+ i++;
+ if (i >= 0 && i < len)
+ a1 = tab[i];
+ else
+ a1 = 0;
+ return fast_shr_dec(a0, shift) +
+ fast_urem(a1, &mp_pow_div[LIMB_DIGITS - shift]) *
+ mp_pow_dec[shift];
+ }
+}
+#endif
+
+/* return the addend for rounding. Note that prec can be <= 0 for bf_rint() */
+static int bfdec_get_rnd_add(int *pret, const bfdec_t *r, limb_t l,
+ slimb_t prec, int rnd_mode)
+{
+ int add_one, inexact;
+ limb_t digit1, digit0;
+
+ // bfdec_print_str("get_rnd_add", r);
+ if (rnd_mode == BF_RNDF) {
+ digit0 = 1; /* faithful rounding does not honor the INEXACT flag */
+ } else {
+ /* starting limb for bit 'prec + 1' */
+ digit0 = scan_digit_nz(r, l * LIMB_DIGITS - 1 - bf_max(0, prec + 1));
+ }
+
+ /* get the digit at 'prec' */
+ digit1 = get_digit(r->tab, l, l * LIMB_DIGITS - 1 - prec);
+ inexact = (digit1 | digit0) != 0;
+
+ add_one = 0;
+ switch(rnd_mode) {
+ case BF_RNDZ:
+ break;
+ case BF_RNDN:
+ if (digit1 == 5) {
+ if (digit0) {
+ add_one = 1;
+ } else {
+ /* round to even */
+ add_one =
+ get_digit(r->tab, l, l * LIMB_DIGITS - 1 - (prec - 1)) & 1;
+ }
+ } else if (digit1 > 5) {
+ add_one = 1;
+ }
+ break;
+ case BF_RNDD:
+ case BF_RNDU:
+ if (r->sign == (rnd_mode == BF_RNDD))
+ add_one = inexact;
+ break;
+ case BF_RNDNA:
+ case BF_RNDF:
+ add_one = (digit1 >= 5);
+ break;
+ case BF_RNDA:
+ add_one = inexact;
+ break;
+ default:
+ abort();
+ }
+
+ if (inexact)
+ *pret |= BF_ST_INEXACT;
+ return add_one;
+}
+
+/* round to prec1 bits assuming 'r' is non zero and finite. 'r' is
+ assumed to have length 'l' (1 <= l <= r->len). prec1 can be
+ BF_PREC_INF. BF_FLAG_SUBNORMAL is not supported. Cannot fail with
+ BF_ST_MEM_ERROR.
+ */
+static int __bfdec_round(bfdec_t *r, limb_t prec1, bf_flags_t flags, limb_t l)
+{
+ int shift, add_one, rnd_mode, ret;
+ slimb_t i, bit_pos, pos, e_min, e_max, e_range, prec;
+
+ /* XXX: align to IEEE 754 2008 for decimal numbers ? */
+ e_range = (limb_t)1 << (bf_get_exp_bits(flags) - 1);
+ e_min = -e_range + 3;
+ e_max = e_range;
+
+ if (flags & BF_FLAG_RADPNT_PREC) {
+ /* 'prec' is the precision after the decimal point */
+ if (prec1 != BF_PREC_INF)
+ prec = r->expn + prec1;
+ else
+ prec = prec1;
+ } else if (unlikely(r->expn < e_min) && (flags & BF_FLAG_SUBNORMAL)) {
+ /* restrict the precision in case of potentially subnormal
+ result */
+ assert(prec1 != BF_PREC_INF);
+ prec = prec1 - (e_min - r->expn);
+ } else {
+ prec = prec1;
+ }
+
+ /* round to prec bits */
+ rnd_mode = flags & BF_RND_MASK;
+ ret = 0;
+ add_one = bfdec_get_rnd_add(&ret, r, l, prec, rnd_mode);
+
+ if (prec <= 0) {
+ if (add_one) {
+ bfdec_resize(r, 1); /* cannot fail because r is non zero */
+ r->tab[0] = BF_DEC_BASE / 10;
+ r->expn += 1 - prec;
+ ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;
+ return ret;
+ } else {
+ goto underflow;
+ }
+ } else if (add_one) {
+ limb_t carry;
+
+ /* add one starting at digit 'prec - 1' */
+ bit_pos = l * LIMB_DIGITS - 1 - (prec - 1);
+ pos = bit_pos / LIMB_DIGITS;
+ carry = mp_pow_dec[bit_pos % LIMB_DIGITS];
+ carry = mp_add_ui_dec(r->tab + pos, carry, l - pos);
+ if (carry) {
+ /* shift right by one digit */
+ mp_shr_dec(r->tab + pos, r->tab + pos, l - pos, 1, 1);
+ r->expn++;
+ }
+ }
+
+ /* check underflow */
+ if (unlikely(r->expn < e_min)) {
+ if (flags & BF_FLAG_SUBNORMAL) {
+ /* if inexact, also set the underflow flag */
+ if (ret & BF_ST_INEXACT)
+ ret |= BF_ST_UNDERFLOW;
+ } else {
+ underflow:
+ bfdec_set_zero(r, r->sign);
+ ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;
+ return ret;
+ }
+ }
+
+ /* check overflow */
+ if (unlikely(r->expn > e_max)) {
+ bfdec_set_inf(r, r->sign);
+ ret |= BF_ST_OVERFLOW | BF_ST_INEXACT;
+ return ret;
+ }
+
+ /* keep the bits starting at 'prec - 1' */
+ bit_pos = l * LIMB_DIGITS - 1 - (prec - 1);
+ i = floor_div(bit_pos, LIMB_DIGITS);
+ if (i >= 0) {
+ shift = smod(bit_pos, LIMB_DIGITS);
+ if (shift != 0) {
+ r->tab[i] = fast_shr_dec(r->tab[i], shift) *
+ mp_pow_dec[shift];
+ }
+ } else {
+ i = 0;
+ }
+ /* remove trailing zeros */
+ while (r->tab[i] == 0)
+ i++;
+ if (i > 0) {
+ l -= i;
+ memmove(r->tab, r->tab + i, l * sizeof(limb_t));
+ }
+ bfdec_resize(r, l); /* cannot fail */
+ return ret;
+}
+
+/* Cannot fail with BF_ST_MEM_ERROR. */
+int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags)
+{
+ if (r->len == 0)
+ return 0;
+ return __bfdec_round(r, prec, flags, r->len);
+}
+
+/* 'r' must be a finite number. Cannot fail with BF_ST_MEM_ERROR. */
+int bfdec_normalize_and_round(bfdec_t *r, limb_t prec1, bf_flags_t flags)
+{
+ limb_t l, v;
+ int shift, ret;
+
+ // bfdec_print_str("bf_renorm", r);
+ l = r->len;
+ while (l > 0 && r->tab[l - 1] == 0)
+ l--;
+ if (l == 0) {
+ /* zero */
+ r->expn = BF_EXP_ZERO;
+ bfdec_resize(r, 0); /* cannot fail */
+ ret = 0;
+ } else {
+ r->expn -= (r->len - l) * LIMB_DIGITS;
+ /* shift to have the MSB set to '1' */
+ v = r->tab[l - 1];
+ shift = clz_dec(v);
+ if (shift != 0) {
+ mp_shl_dec(r->tab, r->tab, l, shift, 0);
+ r->expn -= shift;
+ }
+ ret = __bfdec_round(r, prec1, flags, l);
+ }
+ // bf_print_str("r_final", r);
+ return ret;
+}
+
+int bfdec_set_ui(bfdec_t *r, uint64_t v)
+{
+#if LIMB_BITS == 32
+ if (v >= BF_DEC_BASE * BF_DEC_BASE) {
+ if (bfdec_resize(r, 3))
+ goto fail;
+ r->tab[0] = v % BF_DEC_BASE;
+ v /= BF_DEC_BASE;
+ r->tab[1] = v % BF_DEC_BASE;
+ r->tab[2] = v / BF_DEC_BASE;
+ r->expn = 3 * LIMB_DIGITS;
+ } else
+#endif
+ if (v >= BF_DEC_BASE) {
+ if (bfdec_resize(r, 2))
+ goto fail;
+ r->tab[0] = v % BF_DEC_BASE;
+ r->tab[1] = v / BF_DEC_BASE;
+ r->expn = 2 * LIMB_DIGITS;
+ } else {
+ if (bfdec_resize(r, 1))
+ goto fail;
+ r->tab[0] = v;
+ r->expn = LIMB_DIGITS;
+ }
+ r->sign = 0;
+ return bfdec_normalize_and_round(r, BF_PREC_INF, 0);
+ fail:
+ bfdec_set_nan(r);
+ return BF_ST_MEM_ERROR;
+}
+
+int bfdec_set_si(bfdec_t *r, int64_t v)
+{
+ int ret;
+ if (v < 0) {
+ ret = bfdec_set_ui(r, -v);
+ r->sign = 1;
+ } else {
+ ret = bfdec_set_ui(r, v);
+ }
+ return ret;
+}
+
+static int bfdec_add_internal(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, bf_flags_t flags, int b_neg)
+{
+ bf_context_t *s = r->ctx;
+ int is_sub, cmp_res, a_sign, b_sign, ret;
+
+ a_sign = a->sign;
+ b_sign = b->sign ^ b_neg;
+ is_sub = a_sign ^ b_sign;
+ cmp_res = bfdec_cmpu(a, b);
+ if (cmp_res < 0) {
+ const bfdec_t *tmp;
+ tmp = a;
+ a = b;
+ b = tmp;
+ a_sign = b_sign; /* b_sign is never used later */
+ }
+ /* abs(a) >= abs(b) */
+ if (cmp_res == 0 && is_sub && a->expn < BF_EXP_INF) {
+ /* zero result */
+ bfdec_set_zero(r, (flags & BF_RND_MASK) == BF_RNDD);
+ ret = 0;
+ } else if (a->len == 0 || b->len == 0) {
+ ret = 0;
+ if (a->expn >= BF_EXP_INF) {
+ if (a->expn == BF_EXP_NAN) {
+ /* at least one operand is NaN */
+ bfdec_set_nan(r);
+ ret = 0;
+ } else if (b->expn == BF_EXP_INF && is_sub) {
+ /* infinities with different signs */
+ bfdec_set_nan(r);
+ ret = BF_ST_INVALID_OP;
+ } else {
+ bfdec_set_inf(r, a_sign);
+ }
+ } else {
+ /* at least one zero and not subtract */
+ if (bfdec_set(r, a))
+ return BF_ST_MEM_ERROR;
+ r->sign = a_sign;
+ goto renorm;
+ }
+ } else {
+ slimb_t d, a_offset, b_offset, i, r_len;
+ limb_t carry;
+ limb_t *b1_tab;
+ int b_shift;
+ mp_size_t b1_len;
+
+ d = a->expn - b->expn;
+
+ /* XXX: not efficient in time and memory if the precision is
+ not infinite */
+ r_len = bf_max(a->len, b->len + (d + LIMB_DIGITS - 1) / LIMB_DIGITS);
+ if (bfdec_resize(r, r_len))
+ goto fail;
+ r->sign = a_sign;
+ r->expn = a->expn;
+
+ a_offset = r_len - a->len;
+ for(i = 0; i < a_offset; i++)
+ r->tab[i] = 0;
+ for(i = 0; i < a->len; i++)
+ r->tab[a_offset + i] = a->tab[i];
+
+ b_shift = d % LIMB_DIGITS;
+ if (b_shift == 0) {
+ b1_len = b->len;
+ b1_tab = (limb_t *)b->tab;
+ } else {
+ b1_len = b->len + 1;
+ b1_tab = bf_malloc(s, sizeof(limb_t) * b1_len);
+ if (!b1_tab)
+ goto fail;
+ b1_tab[0] = mp_shr_dec(b1_tab + 1, b->tab, b->len, b_shift, 0) *
+ mp_pow_dec[LIMB_DIGITS - b_shift];
+ }
+ b_offset = r_len - (b->len + (d + LIMB_DIGITS - 1) / LIMB_DIGITS);
+
+ if (is_sub) {
+ carry = mp_sub_dec(r->tab + b_offset, r->tab + b_offset,
+ b1_tab, b1_len, 0);
+ if (carry != 0) {
+ carry = mp_sub_ui_dec(r->tab + b_offset + b1_len, carry,
+ r_len - (b_offset + b1_len));
+ assert(carry == 0);
+ }
+ } else {
+ carry = mp_add_dec(r->tab + b_offset, r->tab + b_offset,
+ b1_tab, b1_len, 0);
+ if (carry != 0) {
+ carry = mp_add_ui_dec(r->tab + b_offset + b1_len, carry,
+ r_len - (b_offset + b1_len));
+ }
+ if (carry != 0) {
+ if (bfdec_resize(r, r_len + 1)) {
+ if (b_shift != 0)
+ bf_free(s, b1_tab);
+ goto fail;
+ }
+ r->tab[r_len] = 1;
+ r->expn += LIMB_DIGITS;
+ }
+ }
+ if (b_shift != 0)
+ bf_free(s, b1_tab);
+ renorm:
+ ret = bfdec_normalize_and_round(r, prec, flags);
+ }
+ return ret;
+ fail:
+ bfdec_set_nan(r);
+ return BF_ST_MEM_ERROR;
+}
+
+static int __bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
+ bf_flags_t flags)
+{
+ return bfdec_add_internal(r, a, b, prec, flags, 0);
+}
+
+static int __bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
+ bf_flags_t flags)
+{
+ return bfdec_add_internal(r, a, b, prec, flags, 1);
+}
+
+int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
+ bf_flags_t flags)
+{
+ return bf_op2((bf_t *)r, (bf_t *)a, (bf_t *)b, prec, flags,
+ (bf_op2_func_t *)__bfdec_add);
+}
+
+int bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
+ bf_flags_t flags)
+{
+ return bf_op2((bf_t *)r, (bf_t *)a, (bf_t *)b, prec, flags,
+ (bf_op2_func_t *)__bfdec_sub);
+}
+
+int bfdec_mul(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
+ bf_flags_t flags)
+{
+ int ret, r_sign;
+
+ if (a->len < b->len) {
+ const bfdec_t *tmp = a;
+ a = b;
+ b = tmp;
+ }
+ r_sign = a->sign ^ b->sign;
+ /* here b->len <= a->len */
+ if (b->len == 0) {
+ if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
+ bfdec_set_nan(r);
+ ret = 0;
+ } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_INF) {
+ if ((a->expn == BF_EXP_INF && b->expn == BF_EXP_ZERO) ||
+ (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_INF)) {
+ bfdec_set_nan(r);
+ ret = BF_ST_INVALID_OP;
+ } else {
+ bfdec_set_inf(r, r_sign);
+ ret = 0;
+ }
+ } else {
+ bfdec_set_zero(r, r_sign);
+ ret = 0;
+ }
+ } else {
+ bfdec_t tmp, *r1 = NULL;
+ limb_t a_len, b_len;
+ limb_t *a_tab, *b_tab;
+
+ a_len = a->len;
+ b_len = b->len;
+ a_tab = a->tab;
+ b_tab = b->tab;
+
+ if (r == a || r == b) {
+ bfdec_init(r->ctx, &tmp);
+ r1 = r;
+ r = &tmp;
+ }
+ if (bfdec_resize(r, a_len + b_len)) {
+ bfdec_set_nan(r);
+ ret = BF_ST_MEM_ERROR;
+ goto done;
+ }
+ mp_mul_basecase_dec(r->tab, a_tab, a_len, b_tab, b_len);
+ r->sign = r_sign;
+ r->expn = a->expn + b->expn;
+ ret = bfdec_normalize_and_round(r, prec, flags);
+ done:
+ if (r == &tmp)
+ bfdec_move(r1, &tmp);
+ }
+ return ret;
+}
+
+int bfdec_mul_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,
+ bf_flags_t flags)
+{
+ bfdec_t b;
+ int ret;
+ bfdec_init(r->ctx, &b);
+ ret = bfdec_set_si(&b, b1);
+ ret |= bfdec_mul(r, a, &b, prec, flags);
+ bfdec_delete(&b);
+ return ret;
+}
+
+int bfdec_add_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,
+ bf_flags_t flags)
+{
+ bfdec_t b;
+ int ret;
+
+ bfdec_init(r->ctx, &b);
+ ret = bfdec_set_si(&b, b1);
+ ret |= bfdec_add(r, a, &b, prec, flags);
+ bfdec_delete(&b);
+ return ret;
+}
+
+static int __bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b,
+ limb_t prec, bf_flags_t flags)
+{
+ int ret, r_sign;
+ limb_t n, nb, precl;
+
+ r_sign = a->sign ^ b->sign;
+ if (a->expn >= BF_EXP_INF || b->expn >= BF_EXP_INF) {
+ if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
+ bfdec_set_nan(r);
+ return 0;
+ } else if (a->expn == BF_EXP_INF && b->expn == BF_EXP_INF) {
+ bfdec_set_nan(r);
+ return BF_ST_INVALID_OP;
+ } else if (a->expn == BF_EXP_INF) {
+ bfdec_set_inf(r, r_sign);
+ return 0;
+ } else {
+ bfdec_set_zero(r, r_sign);
+ return 0;
+ }
+ } else if (a->expn == BF_EXP_ZERO) {
+ if (b->expn == BF_EXP_ZERO) {
+ bfdec_set_nan(r);
+ return BF_ST_INVALID_OP;
+ } else {
+ bfdec_set_zero(r, r_sign);
+ return 0;
+ }
+ } else if (b->expn == BF_EXP_ZERO) {
+ bfdec_set_inf(r, r_sign);
+ return BF_ST_DIVIDE_ZERO;
+ }
+
+ nb = b->len;
+ if (prec == BF_PREC_INF) {
+ /* infinite precision: return BF_ST_INVALID_OP if not an exact
+ result */
+ /* XXX: check */
+ precl = nb + 1;
+ } else if (flags & BF_FLAG_RADPNT_PREC) {
+ /* number of digits after the decimal point */
+ /* XXX: check (2 extra digits for rounding + 2 digits) */
+ precl = (bf_max(a->expn - b->expn, 0) + 2 +
+ prec + 2 + LIMB_DIGITS - 1) / LIMB_DIGITS;
+ } else {
+ /* number of limbs of the quotient (2 extra digits for rounding) */
+ precl = (prec + 2 + LIMB_DIGITS - 1) / LIMB_DIGITS;
+ }
+ n = bf_max(a->len, precl);
+
+ {
+ limb_t *taba, na, i;
+ slimb_t d;
+
+ na = n + nb;
+ taba = bf_malloc(r->ctx, (na + 1) * sizeof(limb_t));
+ if (!taba)
+ goto fail;
+ d = na - a->len;
+ memset(taba, 0, d * sizeof(limb_t));
+ memcpy(taba + d, a->tab, a->len * sizeof(limb_t));
+ if (bfdec_resize(r, n + 1))
+ goto fail1;
+ if (mp_div_dec(r->ctx, r->tab, taba, na, b->tab, nb)) {
+ fail1:
+ bf_free(r->ctx, taba);
+ goto fail;
+ }
+ /* see if non zero remainder */
+ for(i = 0; i < nb; i++) {
+ if (taba[i] != 0)
+ break;
+ }
+ bf_free(r->ctx, taba);
+ if (i != nb) {
+ if (prec == BF_PREC_INF) {
+ bfdec_set_nan(r);
+ return BF_ST_INVALID_OP;
+ } else {
+ r->tab[0] |= 1;
+ }
+ }
+ r->expn = a->expn - b->expn + LIMB_DIGITS;
+ r->sign = r_sign;
+ ret = bfdec_normalize_and_round(r, prec, flags);
+ }
+ return ret;
+ fail:
+ bfdec_set_nan(r);
+ return BF_ST_MEM_ERROR;
+}
+
+int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
+ bf_flags_t flags)
+{
+ return bf_op2((bf_t *)r, (bf_t *)a, (bf_t *)b, prec, flags,
+ (bf_op2_func_t *)__bfdec_div);
+}
+
+/* a and b must be finite numbers with a >= 0 and b > 0. 'q' is the
+ integer defined as floor(a/b) and r = a - q * b. */
+static void bfdec_tdivremu(bf_context_t *s, bfdec_t *q, bfdec_t *r,
+ const bfdec_t *a, const bfdec_t *b)
+{
+ if (bfdec_cmpu(a, b) < 0) {
+ bfdec_set_ui(q, 0);
+ bfdec_set(r, a);
+ } else {
+ bfdec_div(q, a, b, 0, BF_RNDZ | BF_FLAG_RADPNT_PREC);
+ bfdec_mul(r, q, b, BF_PREC_INF, BF_RNDZ);
+ bfdec_sub(r, a, r, BF_PREC_INF, BF_RNDZ);
+ }
+}
+
+/* division and remainder.
+
+ rnd_mode is the rounding mode for the quotient. The additional
+ rounding mode BF_RND_EUCLIDIAN is supported.
+
+ 'q' is an integer. 'r' is rounded with prec and flags (prec can be
+ BF_PREC_INF).
+*/
+int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b,
+ limb_t prec, bf_flags_t flags, int rnd_mode)
+{
+ bf_context_t *s = q->ctx;
+ bfdec_t a1_s, *a1 = &a1_s;
+ bfdec_t b1_s, *b1 = &b1_s;
+ bfdec_t r1_s, *r1 = &r1_s;
+ int q_sign, res;
+ BOOL is_ceil, is_rndn;
+
+ assert(q != a && q != b);
+ assert(r != a && r != b);
+ assert(q != r);
+
+ if (a->len == 0 || b->len == 0) {
+ bfdec_set_zero(q, 0);
+ if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
+ bfdec_set_nan(r);
+ return 0;
+ } else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_ZERO) {
+ bfdec_set_nan(r);
+ return BF_ST_INVALID_OP;
+ } else {
+ bfdec_set(r, a);
+ return bfdec_round(r, prec, flags);
+ }
+ }
+
+ q_sign = a->sign ^ b->sign;
+ is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);
+ switch(rnd_mode) {
+ default:
+ case BF_RNDZ:
+ case BF_RNDN:
+ case BF_RNDNA:
+ is_ceil = FALSE;
+ break;
+ case BF_RNDD:
+ is_ceil = q_sign;
+ break;
+ case BF_RNDU:
+ is_ceil = q_sign ^ 1;
+ break;
+ case BF_RNDA:
+ is_ceil = TRUE;
+ break;
+ case BF_DIVREM_EUCLIDIAN:
+ is_ceil = a->sign;
+ break;
+ }
+
+ a1->expn = a->expn;
+ a1->tab = a->tab;
+ a1->len = a->len;
+ a1->sign = 0;
+
+ b1->expn = b->expn;
+ b1->tab = b->tab;
+ b1->len = b->len;
+ b1->sign = 0;
+
+ // bfdec_print_str("a1", a1);
+ // bfdec_print_str("b1", b1);
+ /* XXX: could improve to avoid having a large 'q' */
+ bfdec_tdivremu(s, q, r, a1, b1);
+ if (bfdec_is_nan(q) || bfdec_is_nan(r))
+ goto fail;
+ // bfdec_print_str("q", q);
+ // bfdec_print_str("r", r);
+
+ if (r->len != 0) {
+ if (is_rndn) {
+ bfdec_init(s, r1);
+ if (bfdec_set(r1, r))
+ goto fail;
+ if (bfdec_mul_si(r1, r1, 2, BF_PREC_INF, BF_RNDZ)) {
+ bfdec_delete(r1);
+ goto fail;
+ }
+ res = bfdec_cmpu(r1, b);
+ bfdec_delete(r1);
+ if (res > 0 ||
+ (res == 0 &&
+ (rnd_mode == BF_RNDNA ||
+ (get_digit(q->tab, q->len, q->len * LIMB_DIGITS - q->expn) & 1) != 0))) {
+ goto do_sub_r;
+ }
+ } else if (is_ceil) {
+ do_sub_r:
+ res = bfdec_add_si(q, q, 1, BF_PREC_INF, BF_RNDZ);
+ res |= bfdec_sub(r, r, b1, BF_PREC_INF, BF_RNDZ);
+ if (res & BF_ST_MEM_ERROR)
+ goto fail;
+ }
+ }
+
+ r->sign ^= a->sign;
+ q->sign = q_sign;
+ return bfdec_round(r, prec, flags);
+ fail:
+ bfdec_set_nan(q);
+ bfdec_set_nan(r);
+ return BF_ST_MEM_ERROR;
+}
+
+int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
+ bf_flags_t flags, int rnd_mode)
+{
+ bfdec_t q_s, *q = &q_s;
+ int ret;
+
+ bfdec_init(r->ctx, q);
+ ret = bfdec_divrem(q, r, a, b, prec, flags, rnd_mode);
+ bfdec_delete(q);
+ return ret;
+}
+
+/* convert to integer (infinite precision) */
+int bfdec_rint(bfdec_t *r, int rnd_mode)
+{
+ return bfdec_round(r, 0, rnd_mode | BF_FLAG_RADPNT_PREC);
+}
+
+int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags)
+{
+ bf_context_t *s = a->ctx;
+ int ret, k;
+ limb_t *a1, v;
+ slimb_t n, n1, prec1;
+ limb_t res;
+
+ assert(r != a);
+
+ if (a->len == 0) {
+ if (a->expn == BF_EXP_NAN) {
+ bfdec_set_nan(r);
+ } else if (a->expn == BF_EXP_INF && a->sign) {
+ goto invalid_op;
+ } else {
+ bfdec_set(r, a);
+ }
+ ret = 0;
+ } else if (a->sign || prec == BF_PREC_INF) {
+ invalid_op:
+ bfdec_set_nan(r);
+ ret = BF_ST_INVALID_OP;
+ } else {
+ if (flags & BF_FLAG_RADPNT_PREC) {
+ prec1 = bf_max(floor_div(a->expn + 1, 2) + prec, 1);
+ } else {
+ prec1 = prec;
+ }
+ /* convert the mantissa to an integer with at least 2 *
+ prec + 4 digits */
+ n = (2 * (prec1 + 2) + 2 * LIMB_DIGITS - 1) / (2 * LIMB_DIGITS);
+ if (bfdec_resize(r, n))
+ goto fail;
+ a1 = bf_malloc(s, sizeof(limb_t) * 2 * n);
+ if (!a1)
+ goto fail;
+ n1 = bf_min(2 * n, a->len);
+ memset(a1, 0, (2 * n - n1) * sizeof(limb_t));
+ memcpy(a1 + 2 * n - n1, a->tab + a->len - n1, n1 * sizeof(limb_t));
+ if (a->expn & 1) {
+ res = mp_shr_dec(a1, a1, 2 * n, 1, 0);
+ } else {
+ res = 0;
+ }
+ /* normalize so that a1 >= B^(2*n)/4. Not need for n = 1
+ because mp_sqrtrem2_dec already does it */
+ k = 0;
+ if (n > 1) {
+ v = a1[2 * n - 1];
+ while (v < BF_DEC_BASE / 4) {
+ k++;
+ v *= 4;
+ }
+ if (k != 0)
+ mp_mul1_dec(a1, a1, 2 * n, 1 << (2 * k), 0);
+ }
+ if (mp_sqrtrem_dec(s, r->tab, a1, n)) {
+ bf_free(s, a1);
+ goto fail;
+ }
+ if (k != 0)
+ mp_div1_dec(r->tab, r->tab, n, 1 << k, 0);
+ if (!res) {
+ res = mp_scan_nz(a1, n + 1);
+ }
+ bf_free(s, a1);
+ if (!res) {
+ res = mp_scan_nz(a->tab, a->len - n1);
+ }
+ if (res != 0)
+ r->tab[0] |= 1;
+ r->sign = 0;
+ r->expn = (a->expn + 1) >> 1;
+ ret = bfdec_round(r, prec, flags);
+ }
+ return ret;
+ fail:
+ bfdec_set_nan(r);
+ return BF_ST_MEM_ERROR;
+}
+
+/* The rounding mode is always BF_RNDZ. Return BF_ST_OVERFLOW if there
+ is an overflow and 0 otherwise. No memory error is possible. */
+int bfdec_get_int32(int *pres, const bfdec_t *a)
+{
+ uint32_t v;
+ int ret;
+ if (a->expn >= BF_EXP_INF) {
+ ret = 0;
+ if (a->expn == BF_EXP_INF) {
+ v = (uint32_t)INT32_MAX + a->sign;
+ /* XXX: return overflow ? */
+ } else {
+ v = INT32_MAX;
+ }
+ } else if (a->expn <= 0) {
+ v = 0;
+ ret = 0;
+ } else if (a->expn <= 9) {
+ v = fast_shr_dec(a->tab[a->len - 1], LIMB_DIGITS - a->expn);
+ if (a->sign)
+ v = -v;
+ ret = 0;
+ } else if (a->expn == 10) {
+ uint64_t v1;
+ uint32_t v_max;
+#if LIMB_BITS == 64
+ v1 = fast_shr_dec(a->tab[a->len - 1], LIMB_DIGITS - a->expn);
+#else
+ v1 = (uint64_t)a->tab[a->len - 1] * 10 +
+ get_digit(a->tab, a->len, (a->len - 1) * LIMB_DIGITS - 1);
+#endif
+ v_max = (uint32_t)INT32_MAX + a->sign;
+ if (v1 > v_max) {
+ v = v_max;
+ ret = BF_ST_OVERFLOW;
+ } else {
+ v = v1;
+ if (a->sign)
+ v = -v;
+ ret = 0;
+ }
+ } else {
+ v = (uint32_t)INT32_MAX + a->sign;
+ ret = BF_ST_OVERFLOW;
+ }
+ *pres = v;
+ return ret;
+}
+
+/* power to an integer with infinite precision */
+int bfdec_pow_ui(bfdec_t *r, const bfdec_t *a, limb_t b)
+{
+ int ret, n_bits, i;
+
+ assert(r != a);
+ if (b == 0)
+ return bfdec_set_ui(r, 1);
+ ret = bfdec_set(r, a);
+ n_bits = LIMB_BITS - clz(b);
+ for(i = n_bits - 2; i >= 0; i--) {
+ ret |= bfdec_mul(r, r, r, BF_PREC_INF, BF_RNDZ);
+ if ((b >> i) & 1)
+ ret |= bfdec_mul(r, r, a, BF_PREC_INF, BF_RNDZ);
+ }
+ return ret;
+}
+
+char *bfdec_ftoa(size_t *plen, const bfdec_t *a, limb_t prec, bf_flags_t flags)
+{
+ return bf_ftoa_internal(plen, (const bf_t *)a, 10, prec, flags, TRUE);
+}
+
+int bfdec_atof(bfdec_t *r, const char *str, const char **pnext,
+ limb_t prec, bf_flags_t flags)
+{
+ slimb_t dummy_exp;
+ return bf_atof_internal((bf_t *)r, &dummy_exp, str, pnext, 10, prec,
+ flags, TRUE);
+}
+
+#endif /* USE_BF_DEC */
+
+#ifdef USE_FFT_MUL
+/***************************************************************/
+/* Integer multiplication with FFT */
+
+/* or LIMB_BITS at bit position 'pos' in tab */
+static inline void put_bits(limb_t *tab, limb_t len, slimb_t pos, limb_t val)
+{
+ limb_t i;
+ int p;
+
+ i = pos >> LIMB_LOG2_BITS;
+ p = pos & (LIMB_BITS - 1);
+ if (i < len)
+ tab[i] |= val << p;
+ if (p != 0) {
+ i++;
+ if (i < len) {
+ tab[i] |= val >> (LIMB_BITS - p);
+ }
+ }
+}
+
+#if defined(__AVX2__)
+
+typedef double NTTLimb;
+
+/* we must have: modulo >= 1 << NTT_MOD_LOG2_MIN */
+#define NTT_MOD_LOG2_MIN 50
+#define NTT_MOD_LOG2_MAX 51
+#define NB_MODS 5
+#define NTT_PROOT_2EXP 39
+static const int ntt_int_bits[NB_MODS] = { 254, 203, 152, 101, 50, };
+
+static const limb_t ntt_mods[NB_MODS] = { 0x00073a8000000001, 0x0007858000000001, 0x0007a38000000001, 0x0007a68000000001, 0x0007fd8000000001,
+};
+
+static const limb_t ntt_proot[2][NB_MODS] = {
+ { 0x00056198d44332c8, 0x0002eb5d640aad39, 0x00047e31eaa35fd0, 0x0005271ac118a150, 0x00075e0ce8442bd5, },
+ { 0x000461169761bcc5, 0x0002dac3cb2da688, 0x0004abc97751e3bf, 0x000656778fc8c485, 0x0000dc6469c269fa, },
+};
+
+static const limb_t ntt_mods_cr[NB_MODS * (NB_MODS - 1) / 2] = {
+ 0x00020e4da740da8e, 0x0004c3dc09c09c1d, 0x000063bd097b4271, 0x000799d8f18f18fd,
+ 0x0005384222222264, 0x000572b07c1f07fe, 0x00035cd08888889a,
+ 0x00066015555557e3, 0x000725960b60b623,
+ 0x0002fc1fa1d6ce12,
+};
+
+#else
+
+typedef limb_t NTTLimb;
+
+#if LIMB_BITS == 64
+
+#define NTT_MOD_LOG2_MIN 61
+#define NTT_MOD_LOG2_MAX 62
+#define NB_MODS 5
+#define NTT_PROOT_2EXP 51
+static const int ntt_int_bits[NB_MODS] = { 307, 246, 185, 123, 61, };
+
+static const limb_t ntt_mods[NB_MODS] = { 0x28d8000000000001, 0x2a88000000000001, 0x2ed8000000000001, 0x3508000000000001, 0x3aa8000000000001,
+};
+
+static const limb_t ntt_proot[2][NB_MODS] = {
+ { 0x1b8ea61034a2bea7, 0x21a9762de58206fb, 0x02ca782f0756a8ea, 0x278384537a3e50a1, 0x106e13fee74ce0ab, },
+ { 0x233513af133e13b8, 0x1d13140d1c6f75f1, 0x12cde57f97e3eeda, 0x0d6149e23cbe654f, 0x36cd204f522a1379, },
+};
+
+static const limb_t ntt_mods_cr[NB_MODS * (NB_MODS - 1) / 2] = {
+ 0x08a9ed097b425eea, 0x18a44aaaaaaaaab3, 0x2493f57f57f57f5d, 0x126b8d0649a7f8d4,
+ 0x09d80ed7303b5ccc, 0x25b8bcf3cf3cf3d5, 0x2ce6ce63398ce638,
+ 0x0e31fad40a57eb59, 0x02a3529fd4a7f52f,
+ 0x3a5493e93e93e94a,
+};
+
+#elif LIMB_BITS == 32
+
+/* we must have: modulo >= 1 << NTT_MOD_LOG2_MIN */
+#define NTT_MOD_LOG2_MIN 29
+#define NTT_MOD_LOG2_MAX 30
+#define NB_MODS 5
+#define NTT_PROOT_2EXP 20
+static const int ntt_int_bits[NB_MODS] = { 148, 119, 89, 59, 29, };
+
+static const limb_t ntt_mods[NB_MODS] = { 0x0000000032b00001, 0x0000000033700001, 0x0000000036d00001, 0x0000000037300001, 0x000000003e500001,
+};
+
+static const limb_t ntt_proot[2][NB_MODS] = {
+ { 0x0000000032525f31, 0x0000000005eb3b37, 0x00000000246eda9f, 0x0000000035f25901, 0x00000000022f5768, },
+ { 0x00000000051eba1a, 0x00000000107be10e, 0x000000001cd574e0, 0x00000000053806e6, 0x000000002cd6bf98, },
+};
+
+static const limb_t ntt_mods_cr[NB_MODS * (NB_MODS - 1) / 2] = {
+ 0x000000000449559a, 0x000000001eba6ca9, 0x000000002ec18e46, 0x000000000860160b,
+ 0x000000000d321307, 0x000000000bf51120, 0x000000000f662938,
+ 0x000000000932ab3e, 0x000000002f40eef8,
+ 0x000000002e760905,
+};
+
+#endif /* LIMB_BITS */
+
+#endif /* !AVX2 */
+
+#if defined(__AVX2__)
+#define NTT_TRIG_K_MAX 18
+#else
+#define NTT_TRIG_K_MAX 19
+#endif
+
+typedef struct BFNTTState {
+ bf_context_t *ctx;
+
+ /* used for mul_mod_fast() */
+ limb_t ntt_mods_div[NB_MODS];
+
+ limb_t ntt_proot_pow[NB_MODS][2][NTT_PROOT_2EXP + 1];
+ limb_t ntt_proot_pow_inv[NB_MODS][2][NTT_PROOT_2EXP + 1];
+ NTTLimb *ntt_trig[NB_MODS][2][NTT_TRIG_K_MAX + 1];
+ /* 1/2^n mod m */
+ limb_t ntt_len_inv[NB_MODS][NTT_PROOT_2EXP + 1][2];
+#if defined(__AVX2__)
+ __m256d ntt_mods_cr_vec[NB_MODS * (NB_MODS - 1) / 2];
+ __m256d ntt_mods_vec[NB_MODS];
+ __m256d ntt_mods_inv_vec[NB_MODS];
+#else
+ limb_t ntt_mods_cr_inv[NB_MODS * (NB_MODS - 1) / 2];
+#endif
+} BFNTTState;
+
+static NTTLimb *get_trig(BFNTTState *s, int k, int inverse, int m_idx);
+
+/* add modulo with up to (LIMB_BITS-1) bit modulo */
+static inline limb_t add_mod(limb_t a, limb_t b, limb_t m)
+{
+ limb_t r;
+ r = a + b;
+ if (r >= m)
+ r -= m;
+ return r;
+}
+
+/* sub modulo with up to LIMB_BITS bit modulo */
+static inline limb_t sub_mod(limb_t a, limb_t b, limb_t m)
+{
+ limb_t r;
+ r = a - b;
+ if (r > a)
+ r += m;
+ return r;
+}
+
+/* return (r0+r1*B) mod m
+ precondition: 0 <= r0+r1*B < 2^(64+NTT_MOD_LOG2_MIN)
+*/
+static inline limb_t mod_fast(dlimb_t r,
+ limb_t m, limb_t m_inv)
+{
+ limb_t a1, q, t0, r1, r0;
+
+ a1 = r >> NTT_MOD_LOG2_MIN;
+
+ q = ((dlimb_t)a1 * m_inv) >> LIMB_BITS;
+ r = r - (dlimb_t)q * m - m * 2;
+ r1 = r >> LIMB_BITS;
+ t0 = (slimb_t)r1 >> 1;
+ r += m & t0;
+ r0 = r;
+ r1 = r >> LIMB_BITS;
+ r0 += m & r1;
+ return r0;
+}
+
+/* faster version using precomputed modulo inverse.
+ precondition: 0 <= a * b < 2^(64+NTT_MOD_LOG2_MIN) */
+static inline limb_t mul_mod_fast(limb_t a, limb_t b,
+ limb_t m, limb_t m_inv)
+{
+ dlimb_t r;
+ r = (dlimb_t)a * (dlimb_t)b;
+ return mod_fast(r, m, m_inv);
+}
+
+static inline limb_t init_mul_mod_fast(limb_t m)
+{
+ dlimb_t t;
+ assert(m < (limb_t)1 << NTT_MOD_LOG2_MAX);
+ assert(m >= (limb_t)1 << NTT_MOD_LOG2_MIN);
+ t = (dlimb_t)1 << (LIMB_BITS + NTT_MOD_LOG2_MIN);
+ return t / m;
+}
+
+/* Faster version used when the multiplier is constant. 0 <= a < 2^64,
+ 0 <= b < m. */
+static inline limb_t mul_mod_fast2(limb_t a, limb_t b,
+ limb_t m, limb_t b_inv)
+{
+ limb_t r, q;
+
+ q = ((dlimb_t)a * (dlimb_t)b_inv) >> LIMB_BITS;
+ r = a * b - q * m;
+ if (r >= m)
+ r -= m;
+ return r;
+}
+
+/* Faster version used when the multiplier is constant. 0 <= a < 2^64,
+ 0 <= b < m. Let r = a * b mod m. The return value is 'r' or 'r +
+ m'. */
+static inline limb_t mul_mod_fast3(limb_t a, limb_t b,
+ limb_t m, limb_t b_inv)
+{
+ limb_t r, q;
+
+ q = ((dlimb_t)a * (dlimb_t)b_inv) >> LIMB_BITS;
+ r = a * b - q * m;
+ return r;
+}
+
+static inline limb_t init_mul_mod_fast2(limb_t b, limb_t m)
+{
+ return ((dlimb_t)b << LIMB_BITS) / m;
+}
+
+#ifdef __AVX2__
+
+static inline limb_t ntt_limb_to_int(NTTLimb a, limb_t m)
+{
+ slimb_t v;
+ v = a;
+ if (v < 0)
+ v += m;
+ if (v >= m)
+ v -= m;
+ return v;
+}
+
+static inline NTTLimb int_to_ntt_limb(limb_t a, limb_t m)
+{
+ return (slimb_t)a;
+}
+
+static inline NTTLimb int_to_ntt_limb2(limb_t a, limb_t m)
+{
+ if (a >= (m / 2))
+ a -= m;
+ return (slimb_t)a;
+}
+
+/* return r + m if r < 0 otherwise r. */
+static inline __m256d ntt_mod1(__m256d r, __m256d m)
+{
+ return _mm256_blendv_pd(r, r + m, r);
+}
+
+/* input: abs(r) < 2 * m. Output: abs(r) < m */
+static inline __m256d ntt_mod(__m256d r, __m256d mf, __m256d m2f)
+{
+ return _mm256_blendv_pd(r, r + m2f, r) - mf;
+}
+
+/* input: abs(a*b) < 2 * m^2, output: abs(r) < m */
+static inline __m256d ntt_mul_mod(__m256d a, __m256d b, __m256d mf,
+ __m256d m_inv)
+{
+ __m256d r, q, ab1, ab0, qm0, qm1;
+ ab1 = a * b;
+ q = _mm256_round_pd(ab1 * m_inv, 0); /* round to nearest */
+ qm1 = q * mf;
+ qm0 = _mm256_fmsub_pd(q, mf, qm1); /* low part */
+ ab0 = _mm256_fmsub_pd(a, b, ab1); /* low part */
+ r = (ab1 - qm1) + (ab0 - qm0);
+ return r;
+}
+
+static void *bf_aligned_malloc(bf_context_t *s, size_t size, size_t align)
+{
+ void *ptr;
+ void **ptr1;
+ ptr = bf_malloc(s, size + sizeof(void *) + align - 1);
+ if (!ptr)
+ return NULL;
+ ptr1 = (void **)(((uintptr_t)ptr + sizeof(void *) + align - 1) &
+ ~(align - 1));
+ ptr1[-1] = ptr;
+ return ptr1;
+}
+
+static void bf_aligned_free(bf_context_t *s, void *ptr)
+{
+ if (!ptr)
+ return;
+ bf_free(s, ((void **)ptr)[-1]);
+}
+
+static void *ntt_malloc(BFNTTState *s, size_t size)
+{
+ return bf_aligned_malloc(s->ctx, size, 64);
+}
+
+static void ntt_free(BFNTTState *s, void *ptr)
+{
+ bf_aligned_free(s->ctx, ptr);
+}
+
+static no_inline int ntt_fft(BFNTTState *s,
+ NTTLimb *out_buf, NTTLimb *in_buf,
+ NTTLimb *tmp_buf, int fft_len_log2,
+ int inverse, int m_idx)
+{
+ limb_t nb_blocks, fft_per_block, p, k, n, stride_in, i, j;
+ NTTLimb *tab_in, *tab_out, *tmp, *trig;
+ __m256d m_inv, mf, m2f, c, a0, a1, b0, b1;
+ limb_t m;
+ int l;
+
+ m = ntt_mods[m_idx];
+
+ m_inv = _mm256_set1_pd(1.0 / (double)m);
+ mf = _mm256_set1_pd(m);
+ m2f = _mm256_set1_pd(m * 2);
+
+ n = (limb_t)1 << fft_len_log2;
+ assert(n >= 8);
+ stride_in = n / 2;
+
+ tab_in = in_buf;
+ tab_out = tmp_buf;
+ trig = get_trig(s, fft_len_log2, inverse, m_idx);
+ if (!trig)
+ return -1;
+ p = 0;
+ for(k = 0; k < stride_in; k += 4) {
+ a0 = _mm256_load_pd(&tab_in[k]);
+ a1 = _mm256_load_pd(&tab_in[k + stride_in]);
+ c = _mm256_load_pd(trig);
+ trig += 4;
+ b0 = ntt_mod(a0 + a1, mf, m2f);
+ b1 = ntt_mul_mod(a0 - a1, c, mf, m_inv);
+ a0 = _mm256_permute2f128_pd(b0, b1, 0x20);
+ a1 = _mm256_permute2f128_pd(b0, b1, 0x31);
+ a0 = _mm256_permute4x64_pd(a0, 0xd8);
+ a1 = _mm256_permute4x64_pd(a1, 0xd8);
+ _mm256_store_pd(&tab_out[p], a0);
+ _mm256_store_pd(&tab_out[p + 4], a1);
+ p += 2 * 4;
+ }
+ tmp = tab_in;
+ tab_in = tab_out;
+ tab_out = tmp;
+
+ trig = get_trig(s, fft_len_log2 - 1, inverse, m_idx);
+ if (!trig)
+ return -1;
+ p = 0;
+ for(k = 0; k < stride_in; k += 4) {
+ a0 = _mm256_load_pd(&tab_in[k]);
+ a1 = _mm256_load_pd(&tab_in[k + stride_in]);
+ c = _mm256_setr_pd(trig[0], trig[0], trig[1], trig[1]);
+ trig += 2;
+ b0 = ntt_mod(a0 + a1, mf, m2f);
+ b1 = ntt_mul_mod(a0 - a1, c, mf, m_inv);
+ a0 = _mm256_permute2f128_pd(b0, b1, 0x20);
+ a1 = _mm256_permute2f128_pd(b0, b1, 0x31);
+ _mm256_store_pd(&tab_out[p], a0);
+ _mm256_store_pd(&tab_out[p + 4], a1);
+ p += 2 * 4;
+ }
+ tmp = tab_in;
+ tab_in = tab_out;
+ tab_out = tmp;
+
+ nb_blocks = n / 4;
+ fft_per_block = 4;
+
+ l = fft_len_log2 - 2;
+ while (nb_blocks != 2) {
+ nb_blocks >>= 1;
+ p = 0;
+ k = 0;
+ trig = get_trig(s, l, inverse, m_idx);
+ if (!trig)
+ return -1;
+ for(i = 0; i < nb_blocks; i++) {
+ c = _mm256_set1_pd(trig[0]);
+ trig++;
+ for(j = 0; j < fft_per_block; j += 4) {
+ a0 = _mm256_load_pd(&tab_in[k + j]);
+ a1 = _mm256_load_pd(&tab_in[k + j + stride_in]);
+ b0 = ntt_mod(a0 + a1, mf, m2f);
+ b1 = ntt_mul_mod(a0 - a1, c, mf, m_inv);
+ _mm256_store_pd(&tab_out[p + j], b0);
+ _mm256_store_pd(&tab_out[p + j + fft_per_block], b1);
+ }
+ k += fft_per_block;
+ p += 2 * fft_per_block;
+ }
+ fft_per_block <<= 1;
+ l--;
+ tmp = tab_in;
+ tab_in = tab_out;
+ tab_out = tmp;
+ }
+
+ tab_out = out_buf;
+ for(k = 0; k < stride_in; k += 4) {
+ a0 = _mm256_load_pd(&tab_in[k]);
+ a1 = _mm256_load_pd(&tab_in[k + stride_in]);
+ b0 = ntt_mod(a0 + a1, mf, m2f);
+ b1 = ntt_mod(a0 - a1, mf, m2f);
+ _mm256_store_pd(&tab_out[k], b0);
+ _mm256_store_pd(&tab_out[k + stride_in], b1);
+ }
+ return 0;
+}
+
+static void ntt_vec_mul(BFNTTState *s,
+ NTTLimb *tab1, NTTLimb *tab2, limb_t fft_len_log2,
+ int k_tot, int m_idx)
+{
+ limb_t i, c_inv, n, m;
+ __m256d m_inv, mf, a, b, c;
+
+ m = ntt_mods[m_idx];
+ c_inv = s->ntt_len_inv[m_idx][k_tot][0];
+ m_inv = _mm256_set1_pd(1.0 / (double)m);
+ mf = _mm256_set1_pd(m);
+ c = _mm256_set1_pd(int_to_ntt_limb(c_inv, m));
+ n = (limb_t)1 << fft_len_log2;
+ for(i = 0; i < n; i += 4) {
+ a = _mm256_load_pd(&tab1[i]);
+ b = _mm256_load_pd(&tab2[i]);
+ a = ntt_mul_mod(a, b, mf, m_inv);
+ a = ntt_mul_mod(a, c, mf, m_inv);
+ _mm256_store_pd(&tab1[i], a);
+ }
+}
+
+static no_inline void mul_trig(NTTLimb *buf,
+ limb_t n, limb_t c1, limb_t m, limb_t m_inv1)
+{
+ limb_t i, c2, c3, c4;
+ __m256d c, c_mul, a0, mf, m_inv;
+ assert(n >= 2);
+
+ mf = _mm256_set1_pd(m);
+ m_inv = _mm256_set1_pd(1.0 / (double)m);
+
+ c2 = mul_mod_fast(c1, c1, m, m_inv1);
+ c3 = mul_mod_fast(c2, c1, m, m_inv1);
+ c4 = mul_mod_fast(c2, c2, m, m_inv1);
+ c = _mm256_setr_pd(1, int_to_ntt_limb(c1, m),
+ int_to_ntt_limb(c2, m), int_to_ntt_limb(c3, m));
+ c_mul = _mm256_set1_pd(int_to_ntt_limb(c4, m));
+ for(i = 0; i < n; i += 4) {
+ a0 = _mm256_load_pd(&buf[i]);
+ a0 = ntt_mul_mod(a0, c, mf, m_inv);
+ _mm256_store_pd(&buf[i], a0);
+ c = ntt_mul_mod(c, c_mul, mf, m_inv);
+ }
+}
+
+#else
+
+static void *ntt_malloc(BFNTTState *s, size_t size)
+{
+ return bf_malloc(s->ctx, size);
+}
+
+static void ntt_free(BFNTTState *s, void *ptr)
+{
+ bf_free(s->ctx, ptr);
+}
+
+static inline limb_t ntt_limb_to_int(NTTLimb a, limb_t m)
+{
+ if (a >= m)
+ a -= m;
+ return a;
+}
+
+static inline NTTLimb int_to_ntt_limb(slimb_t a, limb_t m)
+{
+ return a;
+}
+
+static no_inline int ntt_fft(BFNTTState *s, NTTLimb *out_buf, NTTLimb *in_buf,
+ NTTLimb *tmp_buf, int fft_len_log2,
+ int inverse, int m_idx)
+{
+ limb_t nb_blocks, fft_per_block, p, k, n, stride_in, i, j, m, m2;
+ NTTLimb *tab_in, *tab_out, *tmp, a0, a1, b0, b1, c, *trig, c_inv;
+ int l;
+
+ m = ntt_mods[m_idx];
+ m2 = 2 * m;
+ n = (limb_t)1 << fft_len_log2;
+ nb_blocks = n;
+ fft_per_block = 1;
+ stride_in = n / 2;
+ tab_in = in_buf;
+ tab_out = tmp_buf;
+ l = fft_len_log2;
+ while (nb_blocks != 2) {
+ nb_blocks >>= 1;
+ p = 0;
+ k = 0;
+ trig = get_trig(s, l, inverse, m_idx);
+ if (!trig)
+ return -1;
+ for(i = 0; i < nb_blocks; i++) {
+ c = trig[0];
+ c_inv = trig[1];
+ trig += 2;
+ for(j = 0; j < fft_per_block; j++) {
+ a0 = tab_in[k + j];
+ a1 = tab_in[k + j + stride_in];
+ b0 = add_mod(a0, a1, m2);
+ b1 = a0 - a1 + m2;
+ b1 = mul_mod_fast3(b1, c, m, c_inv);
+ tab_out[p + j] = b0;
+ tab_out[p + j + fft_per_block] = b1;
+ }
+ k += fft_per_block;
+ p += 2 * fft_per_block;
+ }
+ fft_per_block <<= 1;
+ l--;
+ tmp = tab_in;
+ tab_in = tab_out;
+ tab_out = tmp;
+ }
+ /* no twiddle in last step */
+ tab_out = out_buf;
+ for(k = 0; k < stride_in; k++) {
+ a0 = tab_in[k];
+ a1 = tab_in[k + stride_in];
+ b0 = add_mod(a0, a1, m2);
+ b1 = sub_mod(a0, a1, m2);
+ tab_out[k] = b0;
+ tab_out[k + stride_in] = b1;
+ }
+ return 0;
+}
+
+static void ntt_vec_mul(BFNTTState *s,
+ NTTLimb *tab1, NTTLimb *tab2, int fft_len_log2,
+ int k_tot, int m_idx)
+{
+ limb_t i, norm, norm_inv, a, n, m, m_inv;
+
+ m = ntt_mods[m_idx];
+ m_inv = s->ntt_mods_div[m_idx];
+ norm = s->ntt_len_inv[m_idx][k_tot][0];
+ norm_inv = s->ntt_len_inv[m_idx][k_tot][1];
+ n = (limb_t)1 << fft_len_log2;
+ for(i = 0; i < n; i++) {
+ a = tab1[i];
+ /* need to reduce the range so that the product is <
+ 2^(LIMB_BITS+NTT_MOD_LOG2_MIN) */
+ if (a >= m)
+ a -= m;
+ a = mul_mod_fast(a, tab2[i], m, m_inv);
+ a = mul_mod_fast3(a, norm, m, norm_inv);
+ tab1[i] = a;
+ }
+}
+
+static no_inline void mul_trig(NTTLimb *buf,
+ limb_t n, limb_t c_mul, limb_t m, limb_t m_inv)
+{
+ limb_t i, c0, c_mul_inv;
+
+ c0 = 1;
+ c_mul_inv = init_mul_mod_fast2(c_mul, m);
+ for(i = 0; i < n; i++) {
+ buf[i] = mul_mod_fast(buf[i], c0, m, m_inv);
+ c0 = mul_mod_fast2(c0, c_mul, m, c_mul_inv);
+ }
+}
+
+#endif /* !AVX2 */
+
+static no_inline NTTLimb *get_trig(BFNTTState *s,
+ int k, int inverse, int m_idx)
+{
+ NTTLimb *tab;
+ limb_t i, n2, c, c_mul, m, c_mul_inv;
+
+ if (k > NTT_TRIG_K_MAX)
+ return NULL;
+
+ tab = s->ntt_trig[m_idx][inverse][k];
+ if (tab)
+ return tab;
+ n2 = (limb_t)1 << (k - 1);
+ m = ntt_mods[m_idx];
+#ifdef __AVX2__
+ tab = ntt_malloc(s, sizeof(NTTLimb) * n2);
+#else
+ tab = ntt_malloc(s, sizeof(NTTLimb) * n2 * 2);
+#endif
+ if (!tab)
+ return NULL;
+ c = 1;
+ c_mul = s->ntt_proot_pow[m_idx][inverse][k];
+ c_mul_inv = s->ntt_proot_pow_inv[m_idx][inverse][k];
+ for(i = 0; i < n2; i++) {
+#ifdef __AVX2__
+ tab[i] = int_to_ntt_limb2(c, m);
+#else
+ tab[2 * i] = int_to_ntt_limb(c, m);
+ tab[2 * i + 1] = init_mul_mod_fast2(c, m);
+#endif
+ c = mul_mod_fast2(c, c_mul, m, c_mul_inv);
+ }
+ s->ntt_trig[m_idx][inverse][k] = tab;
+ return tab;
+}
+
+void fft_clear_cache(bf_context_t *s1)
+{
+ int m_idx, inverse, k;
+ BFNTTState *s = s1->ntt_state;
+ if (s) {
+ for(m_idx = 0; m_idx < NB_MODS; m_idx++) {
+ for(inverse = 0; inverse < 2; inverse++) {
+ for(k = 0; k < NTT_TRIG_K_MAX + 1; k++) {
+ if (s->ntt_trig[m_idx][inverse][k]) {
+ ntt_free(s, s->ntt_trig[m_idx][inverse][k]);
+ s->ntt_trig[m_idx][inverse][k] = NULL;
+ }
+ }
+ }
+ }
+#if defined(__AVX2__)
+ bf_aligned_free(s1, s);
+#else
+ bf_free(s1, s);
+#endif
+ s1->ntt_state = NULL;
+ }
+}
+
+#define STRIP_LEN 16
+
+/* dst = buf1, src = buf2 */
+static int ntt_fft_partial(BFNTTState *s, NTTLimb *buf1,
+ int k1, int k2, limb_t n1, limb_t n2, int inverse,
+ limb_t m_idx)
+{
+ limb_t i, j, c_mul, c0, m, m_inv, strip_len, l;
+ NTTLimb *buf2, *buf3;
+
+ buf2 = NULL;
+ buf3 = ntt_malloc(s, sizeof(NTTLimb) * n1);
+ if (!buf3)
+ goto fail;
+ if (k2 == 0) {
+ if (ntt_fft(s, buf1, buf1, buf3, k1, inverse, m_idx))
+ goto fail;
+ } else {
+ strip_len = STRIP_LEN;
+ buf2 = ntt_malloc(s, sizeof(NTTLimb) * n1 * strip_len);
+ if (!buf2)
+ goto fail;
+ m = ntt_mods[m_idx];
+ m_inv = s->ntt_mods_div[m_idx];
+ c0 = s->ntt_proot_pow[m_idx][inverse][k1 + k2];
+ c_mul = 1;
+ assert((n2 % strip_len) == 0);
+ for(j = 0; j < n2; j += strip_len) {
+ for(i = 0; i < n1; i++) {
+ for(l = 0; l < strip_len; l++) {
+ buf2[i + l * n1] = buf1[i * n2 + (j + l)];
+ }
+ }
+ for(l = 0; l < strip_len; l++) {
+ if (inverse)
+ mul_trig(buf2 + l * n1, n1, c_mul, m, m_inv);
+ if (ntt_fft(s, buf2 + l * n1, buf2 + l * n1, buf3, k1, inverse, m_idx))
+ goto fail;
+ if (!inverse)
+ mul_trig(buf2 + l * n1, n1, c_mul, m, m_inv);
+ c_mul = mul_mod_fast(c_mul, c0, m, m_inv);
+ }
+
+ for(i = 0; i < n1; i++) {
+ for(l = 0; l < strip_len; l++) {
+ buf1[i * n2 + (j + l)] = buf2[i + l *n1];
+ }
+ }
+ }
+ ntt_free(s, buf2);
+ }
+ ntt_free(s, buf3);
+ return 0;
+ fail:
+ ntt_free(s, buf2);
+ ntt_free(s, buf3);
+ return -1;
+}
+
+
+/* dst = buf1, src = buf2, tmp = buf3 */
+static int ntt_conv(BFNTTState *s, NTTLimb *buf1, NTTLimb *buf2,
+ int k, int k_tot, limb_t m_idx)
+{
+ limb_t n1, n2, i;
+ int k1, k2;
+
+ if (k <= NTT_TRIG_K_MAX) {
+ k1 = k;
+ } else {
+ /* recursive split of the FFT */
+ k1 = bf_min(k / 2, NTT_TRIG_K_MAX);
+ }
+ k2 = k - k1;
+ n1 = (limb_t)1 << k1;
+ n2 = (limb_t)1 << k2;
+
+ if (ntt_fft_partial(s, buf1, k1, k2, n1, n2, 0, m_idx))
+ return -1;
+ if (ntt_fft_partial(s, buf2, k1, k2, n1, n2, 0, m_idx))
+ return -1;
+ if (k2 == 0) {
+ ntt_vec_mul(s, buf1, buf2, k, k_tot, m_idx);
+ } else {
+ for(i = 0; i < n1; i++) {
+ ntt_conv(s, buf1 + i * n2, buf2 + i * n2, k2, k_tot, m_idx);
+ }
+ }
+ if (ntt_fft_partial(s, buf1, k1, k2, n1, n2, 1, m_idx))
+ return -1;
+ return 0;
+}
+
+
+static no_inline void limb_to_ntt(BFNTTState *s,
+ NTTLimb *tabr, limb_t fft_len,
+ const limb_t *taba, limb_t a_len, int dpl,
+ int first_m_idx, int nb_mods)
+{
+ slimb_t i, n;
+ dlimb_t a, b;
+ int j, shift;
+ limb_t base_mask1, a0, a1, a2, r, m, m_inv;
+
+#if 0
+ for(i = 0; i < a_len; i++) {
+ printf("%" PRId64 ": " FMT_LIMB "\n",
+ (int64_t)i, taba[i]);
+ }
+#endif
+ memset(tabr, 0, sizeof(NTTLimb) * fft_len * nb_mods);
+ shift = dpl & (LIMB_BITS - 1);
+ if (shift == 0)
+ base_mask1 = -1;
+ else
+ base_mask1 = ((limb_t)1 << shift) - 1;
+ n = bf_min(fft_len, (a_len * LIMB_BITS + dpl - 1) / dpl);
+ for(i = 0; i < n; i++) {
+ a0 = get_bits(taba, a_len, i * dpl);
+ if (dpl <= LIMB_BITS) {
+ a0 &= base_mask1;
+ a = a0;
+ } else {
+ a1 = get_bits(taba, a_len, i * dpl + LIMB_BITS);
+ if (dpl <= (LIMB_BITS + NTT_MOD_LOG2_MIN)) {
+ a = a0 | ((dlimb_t)(a1 & base_mask1) << LIMB_BITS);
+ } else {
+ if (dpl > 2 * LIMB_BITS) {
+ a2 = get_bits(taba, a_len, i * dpl + LIMB_BITS * 2) &
+ base_mask1;
+ } else {
+ a1 &= base_mask1;
+ a2 = 0;
+ }
+ // printf("a=0x%016lx%016lx%016lx\n", a2, a1, a0);
+ a = (a0 >> (LIMB_BITS - NTT_MOD_LOG2_MAX + NTT_MOD_LOG2_MIN)) |
+ ((dlimb_t)a1 << (NTT_MOD_LOG2_MAX - NTT_MOD_LOG2_MIN)) |
+ ((dlimb_t)a2 << (LIMB_BITS + NTT_MOD_LOG2_MAX - NTT_MOD_LOG2_MIN));
+ a0 &= ((limb_t)1 << (LIMB_BITS - NTT_MOD_LOG2_MAX + NTT_MOD_LOG2_MIN)) - 1;
+ }
+ }
+ for(j = 0; j < nb_mods; j++) {
+ m = ntt_mods[first_m_idx + j];
+ m_inv = s->ntt_mods_div[first_m_idx + j];
+ r = mod_fast(a, m, m_inv);
+ if (dpl > (LIMB_BITS + NTT_MOD_LOG2_MIN)) {
+ b = ((dlimb_t)r << (LIMB_BITS - NTT_MOD_LOG2_MAX + NTT_MOD_LOG2_MIN)) | a0;
+ r = mod_fast(b, m, m_inv);
+ }
+ tabr[i + j * fft_len] = int_to_ntt_limb(r, m);
+ }
+ }
+}
+
+#if defined(__AVX2__)
+
+#define VEC_LEN 4
+
+typedef union {
+ __m256d v;
+ double d[4];
+} VecUnion;
+
+static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len,
+ const NTTLimb *buf, int fft_len_log2, int dpl,
+ int nb_mods)
+{
+ const limb_t *mods = ntt_mods + NB_MODS - nb_mods;
+ const __m256d *mods_cr_vec, *mf, *m_inv;
+ VecUnion y[NB_MODS];
+ limb_t u[NB_MODS], carry[NB_MODS], fft_len, base_mask1, r;
+ slimb_t i, len, pos;
+ int j, k, l, shift, n_limb1, p;
+ dlimb_t t;
+
+ j = NB_MODS * (NB_MODS - 1) / 2 - nb_mods * (nb_mods - 1) / 2;
+ mods_cr_vec = s->ntt_mods_cr_vec + j;
+ mf = s->ntt_mods_vec + NB_MODS - nb_mods;
+ m_inv = s->ntt_mods_inv_vec + NB_MODS - nb_mods;
+
+ shift = dpl & (LIMB_BITS - 1);
+ if (shift == 0)
+ base_mask1 = -1;
+ else
+ base_mask1 = ((limb_t)1 << shift) - 1;
+ n_limb1 = ((unsigned)dpl - 1) / LIMB_BITS;
+ for(j = 0; j < NB_MODS; j++)
+ carry[j] = 0;
+ for(j = 0; j < NB_MODS; j++)
+ u[j] = 0; /* avoid warnings */
+ memset(tabr, 0, sizeof(limb_t) * r_len);
+ fft_len = (limb_t)1 << fft_len_log2;
+ len = bf_min(fft_len, (r_len * LIMB_BITS + dpl - 1) / dpl);
+ len = (len + VEC_LEN - 1) & ~(VEC_LEN - 1);
+ i = 0;
+ while (i < len) {
+ for(j = 0; j < nb_mods; j++)
+ y[j].v = *(__m256d *)&buf[i + fft_len * j];
+
+ /* Chinese remainder to get mixed radix representation */
+ l = 0;
+ for(j = 0; j < nb_mods - 1; j++) {
+ y[j].v = ntt_mod1(y[j].v, mf[j]);
+ for(k = j + 1; k < nb_mods; k++) {
+ y[k].v = ntt_mul_mod(y[k].v - y[j].v,
+ mods_cr_vec[l], mf[k], m_inv[k]);
+ l++;
+ }
+ }
+ y[j].v = ntt_mod1(y[j].v, mf[j]);
+
+ for(p = 0; p < VEC_LEN; p++) {
+ /* back to normal representation */
+ u[0] = (int64_t)y[nb_mods - 1].d[p];
+ l = 1;
+ for(j = nb_mods - 2; j >= 1; j--) {
+ r = (int64_t)y[j].d[p];
+ for(k = 0; k < l; k++) {
+ t = (dlimb_t)u[k] * mods[j] + r;
+ r = t >> LIMB_BITS;
+ u[k] = t;
+ }
+ u[l] = r;
+ l++;
+ }
+ /* XXX: for nb_mods = 5, l should be 4 */
+
+ /* last step adds the carry */
+ r = (int64_t)y[0].d[p];
+ for(k = 0; k < l; k++) {
+ t = (dlimb_t)u[k] * mods[j] + r + carry[k];
+ r = t >> LIMB_BITS;
+ u[k] = t;
+ }
+ u[l] = r + carry[l];
+
+#if 0
+ printf("%" PRId64 ": ", i);
+ for(j = nb_mods - 1; j >= 0; j--) {
+ printf(" %019" PRIu64, u[j]);
+ }
+ printf("\n");
+#endif
+
+ /* write the digits */
+ pos = i * dpl;
+ for(j = 0; j < n_limb1; j++) {
+ put_bits(tabr, r_len, pos, u[j]);
+ pos += LIMB_BITS;
+ }
+ put_bits(tabr, r_len, pos, u[n_limb1] & base_mask1);
+ /* shift by dpl digits and set the carry */
+ if (shift == 0) {
+ for(j = n_limb1 + 1; j < nb_mods; j++)
+ carry[j - (n_limb1 + 1)] = u[j];
+ } else {
+ for(j = n_limb1; j < nb_mods - 1; j++) {
+ carry[j - n_limb1] = (u[j] >> shift) |
+ (u[j + 1] << (LIMB_BITS - shift));
+ }
+ carry[nb_mods - 1 - n_limb1] = u[nb_mods - 1] >> shift;
+ }
+ i++;
+ }
+ }
+}
+#else
+static no_inline void ntt_to_limb(BFNTTState *s, limb_t *tabr, limb_t r_len,
+ const NTTLimb *buf, int fft_len_log2, int dpl,
+ int nb_mods)
+{
+ const limb_t *mods = ntt_mods + NB_MODS - nb_mods;
+ const limb_t *mods_cr, *mods_cr_inv;
+ limb_t y[NB_MODS], u[NB_MODS], carry[NB_MODS], fft_len, base_mask1, r;
+ slimb_t i, len, pos;
+ int j, k, l, shift, n_limb1;
+ dlimb_t t;
+
+ j = NB_MODS * (NB_MODS - 1) / 2 - nb_mods * (nb_mods - 1) / 2;
+ mods_cr = ntt_mods_cr + j;
+ mods_cr_inv = s->ntt_mods_cr_inv + j;
+
+ shift = dpl & (LIMB_BITS - 1);
+ if (shift == 0)
+ base_mask1 = -1;
+ else
+ base_mask1 = ((limb_t)1 << shift) - 1;
+ n_limb1 = ((unsigned)dpl - 1) / LIMB_BITS;
+ for(j = 0; j < NB_MODS; j++)
+ carry[j] = 0;
+ for(j = 0; j < NB_MODS; j++)
+ u[j] = 0; /* avoid warnings */
+ memset(tabr, 0, sizeof(limb_t) * r_len);
+ fft_len = (limb_t)1 << fft_len_log2;
+ len = bf_min(fft_len, (r_len * LIMB_BITS + dpl - 1) / dpl);
+ for(i = 0; i < len; i++) {
+ for(j = 0; j < nb_mods; j++) {
+ y[j] = ntt_limb_to_int(buf[i + fft_len * j], mods[j]);
+ }
+
+ /* Chinese remainder to get mixed radix representation */
+ l = 0;
+ for(j = 0; j < nb_mods - 1; j++) {
+ for(k = j + 1; k < nb_mods; k++) {
+ limb_t m;
+ m = mods[k];
+ /* Note: there is no overflow in the sub_mod() because
+ the modulos are sorted by increasing order */
+ y[k] = mul_mod_fast2(y[k] - y[j] + m,
+ mods_cr[l], m, mods_cr_inv[l]);
+ l++;
+ }
+ }
+
+ /* back to normal representation */
+ u[0] = y[nb_mods - 1];
+ l = 1;
+ for(j = nb_mods - 2; j >= 1; j--) {
+ r = y[j];
+ for(k = 0; k < l; k++) {
+ t = (dlimb_t)u[k] * mods[j] + r;
+ r = t >> LIMB_BITS;
+ u[k] = t;
+ }
+ u[l] = r;
+ l++;
+ }
+
+ /* last step adds the carry */
+ r = y[0];
+ for(k = 0; k < l; k++) {
+ t = (dlimb_t)u[k] * mods[j] + r + carry[k];
+ r = t >> LIMB_BITS;
+ u[k] = t;
+ }
+ u[l] = r + carry[l];
+
+#if 0
+ printf("%" PRId64 ": ", (int64_t)i);
+ for(j = nb_mods - 1; j >= 0; j--) {
+ printf(" " FMT_LIMB, u[j]);
+ }
+ printf("\n");
+#endif
+
+ /* write the digits */
+ pos = i * dpl;
+ for(j = 0; j < n_limb1; j++) {
+ put_bits(tabr, r_len, pos, u[j]);
+ pos += LIMB_BITS;
+ }
+ put_bits(tabr, r_len, pos, u[n_limb1] & base_mask1);
+ /* shift by dpl digits and set the carry */
+ if (shift == 0) {
+ for(j = n_limb1 + 1; j < nb_mods; j++)
+ carry[j - (n_limb1 + 1)] = u[j];
+ } else {
+ for(j = n_limb1; j < nb_mods - 1; j++) {
+ carry[j - n_limb1] = (u[j] >> shift) |
+ (u[j + 1] << (LIMB_BITS - shift));
+ }
+ carry[nb_mods - 1 - n_limb1] = u[nb_mods - 1] >> shift;
+ }
+ }
+}
+#endif
+
+static int ntt_static_init(bf_context_t *s1)
+{
+ BFNTTState *s;
+ int inverse, i, j, k, l;
+ limb_t c, c_inv, c_inv2, m, m_inv;
+
+ if (s1->ntt_state)
+ return 0;
+#if defined(__AVX2__)
+ s = bf_aligned_malloc(s1, sizeof(*s), 64);
+#else
+ s = bf_malloc(s1, sizeof(*s));
+#endif
+ if (!s)
+ return -1;
+ memset(s, 0, sizeof(*s));
+ s1->ntt_state = s;
+ s->ctx = s1;
+
+ for(j = 0; j < NB_MODS; j++) {
+ m = ntt_mods[j];
+ m_inv = init_mul_mod_fast(m);
+ s->ntt_mods_div[j] = m_inv;
+#if defined(__AVX2__)
+ s->ntt_mods_vec[j] = _mm256_set1_pd(m);
+ s->ntt_mods_inv_vec[j] = _mm256_set1_pd(1.0 / (double)m);
+#endif
+ c_inv2 = (m + 1) / 2; /* 1/2 */
+ c_inv = 1;
+ for(i = 0; i <= NTT_PROOT_2EXP; i++) {
+ s->ntt_len_inv[j][i][0] = c_inv;
+ s->ntt_len_inv[j][i][1] = init_mul_mod_fast2(c_inv, m);
+ c_inv = mul_mod_fast(c_inv, c_inv2, m, m_inv);
+ }
+
+ for(inverse = 0; inverse < 2; inverse++) {
+ c = ntt_proot[inverse][j];
+ for(i = 0; i < NTT_PROOT_2EXP; i++) {
+ s->ntt_proot_pow[j][inverse][NTT_PROOT_2EXP - i] = c;
+ s->ntt_proot_pow_inv[j][inverse][NTT_PROOT_2EXP - i] =
+ init_mul_mod_fast2(c, m);
+ c = mul_mod_fast(c, c, m, m_inv);
+ }
+ }
+ }
+
+ l = 0;
+ for(j = 0; j < NB_MODS - 1; j++) {
+ for(k = j + 1; k < NB_MODS; k++) {
+#if defined(__AVX2__)
+ s->ntt_mods_cr_vec[l] = _mm256_set1_pd(int_to_ntt_limb2(ntt_mods_cr[l],
+ ntt_mods[k]));
+#else
+ s->ntt_mods_cr_inv[l] = init_mul_mod_fast2(ntt_mods_cr[l],
+ ntt_mods[k]);
+#endif
+ l++;
+ }
+ }
+ return 0;
+}
+
+int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len)
+{
+ int dpl, fft_len_log2, n_bits, nb_mods, dpl_found, fft_len_log2_found;
+ int int_bits, nb_mods_found;
+ limb_t cost, min_cost;
+
+ min_cost = -1;
+ dpl_found = 0;
+ nb_mods_found = 4;
+ fft_len_log2_found = 0;
+ for(nb_mods = 3; nb_mods <= NB_MODS; nb_mods++) {
+ int_bits = ntt_int_bits[NB_MODS - nb_mods];
+ dpl = bf_min((int_bits - 4) / 2,
+ 2 * LIMB_BITS + 2 * NTT_MOD_LOG2_MIN - NTT_MOD_LOG2_MAX);
+ for(;;) {
+ fft_len_log2 = ceil_log2((len * LIMB_BITS + dpl - 1) / dpl);
+ if (fft_len_log2 > NTT_PROOT_2EXP)
+ goto next;
+ n_bits = fft_len_log2 + 2 * dpl;
+ if (n_bits <= int_bits) {
+ cost = ((limb_t)(fft_len_log2 + 1) << fft_len_log2) * nb_mods;
+ // printf("n=%d dpl=%d: cost=%" PRId64 "\n", nb_mods, dpl, (int64_t)cost);
+ if (cost < min_cost) {
+ min_cost = cost;
+ dpl_found = dpl;
+ nb_mods_found = nb_mods;
+ fft_len_log2_found = fft_len_log2;
+ }
+ break;
+ }
+ dpl--;
+ if (dpl == 0)
+ break;
+ }
+ next: ;
+ }
+ if (!dpl_found)
+ abort();
+ /* limit dpl if possible to reduce fixed cost of limb/NTT conversion */
+ if (dpl_found > (LIMB_BITS + NTT_MOD_LOG2_MIN) &&
+ ((limb_t)(LIMB_BITS + NTT_MOD_LOG2_MIN) << fft_len_log2_found) >=
+ len * LIMB_BITS) {
+ dpl_found = LIMB_BITS + NTT_MOD_LOG2_MIN;
+ }
+ *pnb_mods = nb_mods_found;
+ *pdpl = dpl_found;
+ return fft_len_log2_found;
+}
+
+/* return 0 if OK, -1 if memory error */
+static no_inline int fft_mul(bf_context_t *s1,
+ bf_t *res, limb_t *a_tab, limb_t a_len,
+ limb_t *b_tab, limb_t b_len, int mul_flags)
+{
+ BFNTTState *s;
+ int dpl, fft_len_log2, j, nb_mods, reduced_mem;
+ slimb_t len, fft_len;
+ NTTLimb *buf1, *buf2, *ptr;
+#if defined(USE_MUL_CHECK)
+ limb_t ha, hb, hr, h_ref;
+#endif
+
+ if (ntt_static_init(s1))
+ return -1;
+ s = s1->ntt_state;
+
+ /* find the optimal number of digits per limb (dpl) */
+ len = a_len + b_len;
+ fft_len_log2 = bf_get_fft_size(&dpl, &nb_mods, len);
+ fft_len = (uint64_t)1 << fft_len_log2;
+ // printf("len=%" PRId64 " fft_len_log2=%d dpl=%d\n", len, fft_len_log2, dpl);
+#if defined(USE_MUL_CHECK)
+ ha = mp_mod1(a_tab, a_len, BF_CHKSUM_MOD, 0);
+ hb = mp_mod1(b_tab, b_len, BF_CHKSUM_MOD, 0);
+#endif
+ if ((mul_flags & (FFT_MUL_R_OVERLAP_A | FFT_MUL_R_OVERLAP_B)) == 0) {
+ if (!(mul_flags & FFT_MUL_R_NORESIZE))
+ bf_resize(res, 0);
+ } else if (mul_flags & FFT_MUL_R_OVERLAP_B) {
+ limb_t *tmp_tab, tmp_len;
+ /* it is better to free 'b' first */
+ tmp_tab = a_tab;
+ a_tab = b_tab;
+ b_tab = tmp_tab;
+ tmp_len = a_len;
+ a_len = b_len;
+ b_len = tmp_len;
+ }
+ buf1 = ntt_malloc(s, sizeof(NTTLimb) * fft_len * nb_mods);
+ if (!buf1)
+ return -1;
+ limb_to_ntt(s, buf1, fft_len, a_tab, a_len, dpl,
+ NB_MODS - nb_mods, nb_mods);
+ if ((mul_flags & (FFT_MUL_R_OVERLAP_A | FFT_MUL_R_OVERLAP_B)) ==
+ FFT_MUL_R_OVERLAP_A) {
+ if (!(mul_flags & FFT_MUL_R_NORESIZE))
+ bf_resize(res, 0);
+ }
+ reduced_mem = (fft_len_log2 >= 14);
+ if (!reduced_mem) {
+ buf2 = ntt_malloc(s, sizeof(NTTLimb) * fft_len * nb_mods);
+ if (!buf2)
+ goto fail;
+ limb_to_ntt(s, buf2, fft_len, b_tab, b_len, dpl,
+ NB_MODS - nb_mods, nb_mods);
+ if (!(mul_flags & FFT_MUL_R_NORESIZE))
+ bf_resize(res, 0); /* in case res == b */
+ } else {
+ buf2 = ntt_malloc(s, sizeof(NTTLimb) * fft_len);
+ if (!buf2)
+ goto fail;
+ }
+ for(j = 0; j < nb_mods; j++) {
+ if (reduced_mem) {
+ limb_to_ntt(s, buf2, fft_len, b_tab, b_len, dpl,
+ NB_MODS - nb_mods + j, 1);
+ ptr = buf2;
+ } else {
+ ptr = buf2 + fft_len * j;
+ }
+ if (ntt_conv(s, buf1 + fft_len * j, ptr,
+ fft_len_log2, fft_len_log2, j + NB_MODS - nb_mods))
+ goto fail;
+ }
+ if (!(mul_flags & FFT_MUL_R_NORESIZE))
+ bf_resize(res, 0); /* in case res == b and reduced mem */
+ ntt_free(s, buf2);
+ buf2 = NULL;
+ if (!(mul_flags & FFT_MUL_R_NORESIZE)) {
+ if (bf_resize(res, len))
+ goto fail;
+ }
+ ntt_to_limb(s, res->tab, len, buf1, fft_len_log2, dpl, nb_mods);
+ ntt_free(s, buf1);
+#if defined(USE_MUL_CHECK)
+ hr = mp_mod1(res->tab, len, BF_CHKSUM_MOD, 0);
+ h_ref = mul_mod(ha, hb, BF_CHKSUM_MOD);
+ if (hr != h_ref) {
+ printf("ntt_mul_error: len=%" PRId_LIMB " fft_len_log2=%d dpl=%d nb_mods=%d\n",
+ len, fft_len_log2, dpl, nb_mods);
+ // printf("ha=0x" FMT_LIMB" hb=0x" FMT_LIMB " hr=0x" FMT_LIMB " expected=0x" FMT_LIMB "\n", ha, hb, hr, h_ref);
+ exit(1);
+ }
+#endif
+ return 0;
+ fail:
+ ntt_free(s, buf1);
+ ntt_free(s, buf2);
+ return -1;
+}
+
+#else /* USE_FFT_MUL */
+
+int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len)
+{
+ return 0;
+}
+
+#endif /* !USE_FFT_MUL */
diff --git a/src/shared/quickjs/libbf.h b/src/shared/quickjs/libbf.h
new file mode 100644
index 000000000..b247952b1
--- /dev/null
+++ b/src/shared/quickjs/libbf.h
@@ -0,0 +1,543 @@
+/*
+ * Tiny arbitrary precision floating point library
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef LIBBF_H
+#define LIBBF_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__SIZEOF_INT128__) && (INTPTR_MAX >= INT64_MAX)
+#define LIMB_LOG2_BITS 6
+#else
+#define LIMB_LOG2_BITS 5
+#endif
+
+#define LIMB_BITS (1 << LIMB_LOG2_BITS)
+
+#if LIMB_BITS == 64
+typedef __int128 int128_t;
+typedef unsigned __int128 uint128_t;
+typedef int64_t slimb_t;
+typedef uint64_t limb_t;
+typedef uint128_t dlimb_t;
+#define BF_RAW_EXP_MIN INT64_MIN
+#define BF_RAW_EXP_MAX INT64_MAX
+
+#define LIMB_DIGITS 19
+#define BF_DEC_BASE UINT64_C(10000000000000000000)
+
+#else
+
+typedef int32_t slimb_t;
+typedef uint32_t limb_t;
+typedef uint64_t dlimb_t;
+#define BF_RAW_EXP_MIN INT32_MIN
+#define BF_RAW_EXP_MAX INT32_MAX
+
+#define LIMB_DIGITS 9
+#define BF_DEC_BASE 1000000000U
+
+#endif
+
+/* in bits */
+/* minimum number of bits for the exponent */
+#define BF_EXP_BITS_MIN 3
+/* maximum number of bits for the exponent */
+#define BF_EXP_BITS_MAX (LIMB_BITS - 3)
+/* extended range for exponent, used internally */
+#define BF_EXT_EXP_BITS_MAX (BF_EXP_BITS_MAX + 1)
+/* minimum possible precision */
+#define BF_PREC_MIN 2
+/* minimum possible precision */
+#define BF_PREC_MAX (((limb_t)1 << (LIMB_BITS - 2)) - 2)
+/* some operations support infinite precision */
+#define BF_PREC_INF (BF_PREC_MAX + 1) /* infinite precision */
+
+#if LIMB_BITS == 64
+#define BF_CHKSUM_MOD (UINT64_C(975620677) * UINT64_C(9795002197))
+#else
+#define BF_CHKSUM_MOD 975620677U
+#endif
+
+#define BF_EXP_ZERO BF_RAW_EXP_MIN
+#define BF_EXP_INF (BF_RAW_EXP_MAX - 1)
+#define BF_EXP_NAN BF_RAW_EXP_MAX
+
+/* +/-zero is represented with expn = BF_EXP_ZERO and len = 0,
+ +/-infinity is represented with expn = BF_EXP_INF and len = 0,
+ NaN is represented with expn = BF_EXP_NAN and len = 0 (sign is ignored)
+ */
+typedef struct {
+ struct bf_context_t *ctx;
+ int sign;
+ slimb_t expn;
+ limb_t len;
+ limb_t *tab;
+} bf_t;
+
+typedef struct {
+ /* must be kept identical to bf_t */
+ struct bf_context_t *ctx;
+ int sign;
+ slimb_t expn;
+ limb_t len;
+ limb_t *tab;
+} bfdec_t;
+
+typedef enum {
+ BF_RNDN, /* round to nearest, ties to even */
+ BF_RNDZ, /* round to zero */
+ BF_RNDD, /* round to -inf (the code relies on (BF_RNDD xor BF_RNDU) = 1) */
+ BF_RNDU, /* round to +inf */
+ BF_RNDNA, /* round to nearest, ties away from zero */
+ BF_RNDA, /* round away from zero */
+ BF_RNDF, /* faithful rounding (nondeterministic, either RNDD or RNDU,
+ inexact flag is always set) */
+} bf_rnd_t;
+
+/* allow subnormal numbers. Only available if the number of exponent
+ bits is <= BF_EXP_BITS_USER_MAX and prec != BF_PREC_INF. */
+#define BF_FLAG_SUBNORMAL (1 << 3)
+/* 'prec' is the precision after the radix point instead of the whole
+ mantissa. Can only be used with bf_round() and
+ bfdec_[add|sub|mul|div|sqrt|round](). */
+#define BF_FLAG_RADPNT_PREC (1 << 4)
+
+#define BF_RND_MASK 0x7
+#define BF_EXP_BITS_SHIFT 5
+#define BF_EXP_BITS_MASK 0x3f
+
+/* shortcut for bf_set_exp_bits(BF_EXT_EXP_BITS_MAX) */
+#define BF_FLAG_EXT_EXP (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)
+
+/* contains the rounding mode and number of exponents bits */
+typedef uint32_t bf_flags_t;
+
+typedef void *bf_realloc_func_t(void *opaque, void *ptr, size_t size);
+
+typedef struct {
+ bf_t val;
+ limb_t prec;
+} BFConstCache;
+
+typedef struct bf_context_t {
+ void *realloc_opaque;
+ bf_realloc_func_t *realloc_func;
+ BFConstCache log2_cache;
+ BFConstCache pi_cache;
+ struct BFNTTState *ntt_state;
+} bf_context_t;
+
+static inline int bf_get_exp_bits(bf_flags_t flags)
+{
+ int e;
+ e = (flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK;
+ if (e == BF_EXP_BITS_MASK)
+ return BF_EXP_BITS_MAX + 1;
+ else
+ return BF_EXP_BITS_MAX - e;
+}
+
+static inline bf_flags_t bf_set_exp_bits(int n)
+{
+ return ((BF_EXP_BITS_MAX - n) & BF_EXP_BITS_MASK) << BF_EXP_BITS_SHIFT;
+}
+
+/* returned status */
+#define BF_ST_INVALID_OP (1 << 0)
+#define BF_ST_DIVIDE_ZERO (1 << 1)
+#define BF_ST_OVERFLOW (1 << 2)
+#define BF_ST_UNDERFLOW (1 << 3)
+#define BF_ST_INEXACT (1 << 4)
+/* indicate that a memory allocation error occured. NaN is returned */
+#define BF_ST_MEM_ERROR (1 << 5)
+
+#define BF_RADIX_MAX 36 /* maximum radix for bf_atof() and bf_ftoa() */
+
+static inline slimb_t bf_max(slimb_t a, slimb_t b)
+{
+ if (a > b)
+ return a;
+ else
+ return b;
+}
+
+static inline slimb_t bf_min(slimb_t a, slimb_t b)
+{
+ if (a < b)
+ return a;
+ else
+ return b;
+}
+
+void bf_context_init(bf_context_t *s, bf_realloc_func_t *realloc_func,
+ void *realloc_opaque);
+void bf_context_end(bf_context_t *s);
+/* free memory allocated for the bf cache data */
+void bf_clear_cache(bf_context_t *s);
+
+static inline void *bf_realloc(bf_context_t *s, void *ptr, size_t size)
+{
+ return s->realloc_func(s->realloc_opaque, ptr, size);
+}
+
+/* 'size' must be != 0 */
+static inline void *bf_malloc(bf_context_t *s, size_t size)
+{
+ return bf_realloc(s, NULL, size);
+}
+
+static inline void bf_free(bf_context_t *s, void *ptr)
+{
+ /* must test ptr otherwise equivalent to malloc(0) */
+ if (ptr)
+ bf_realloc(s, ptr, 0);
+}
+
+void bf_init(bf_context_t *s, bf_t *r);
+
+static inline void bf_delete(bf_t *r)
+{
+ bf_context_t *s = r->ctx;
+ /* we accept to delete a zeroed bf_t structure */
+ if (s && r->tab) {
+ bf_realloc(s, r->tab, 0);
+ }
+}
+
+static inline void bf_neg(bf_t *r)
+{
+ r->sign ^= 1;
+}
+
+static inline int bf_is_finite(const bf_t *a)
+{
+ return (a->expn < BF_EXP_INF);
+}
+
+static inline int bf_is_nan(const bf_t *a)
+{
+ return (a->expn == BF_EXP_NAN);
+}
+
+static inline int bf_is_zero(const bf_t *a)
+{
+ return (a->expn == BF_EXP_ZERO);
+}
+
+static inline void bf_memcpy(bf_t *r, const bf_t *a)
+{
+ *r = *a;
+}
+
+int bf_set_ui(bf_t *r, uint64_t a);
+int bf_set_si(bf_t *r, int64_t a);
+void bf_set_nan(bf_t *r);
+void bf_set_zero(bf_t *r, int is_neg);
+void bf_set_inf(bf_t *r, int is_neg);
+int bf_set(bf_t *r, const bf_t *a);
+void bf_move(bf_t *r, bf_t *a);
+int bf_get_float64(const bf_t *a, double *pres, bf_rnd_t rnd_mode);
+int bf_set_float64(bf_t *a, double d);
+
+int bf_cmpu(const bf_t *a, const bf_t *b);
+int bf_cmp_full(const bf_t *a, const bf_t *b);
+int bf_cmp(const bf_t *a, const bf_t *b);
+static inline int bf_cmp_eq(const bf_t *a, const bf_t *b)
+{
+ return bf_cmp(a, b) == 0;
+}
+
+static inline int bf_cmp_le(const bf_t *a, const bf_t *b)
+{
+ return bf_cmp(a, b) <= 0;
+}
+
+static inline int bf_cmp_lt(const bf_t *a, const bf_t *b)
+{
+ return bf_cmp(a, b) < 0;
+}
+
+int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
+int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
+int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags);
+int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
+int bf_mul_ui(bf_t *r, const bf_t *a, uint64_t b1, limb_t prec, bf_flags_t flags);
+int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec,
+ bf_flags_t flags);
+int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags);
+int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
+#define BF_DIVREM_EUCLIDIAN BF_RNDF
+int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b,
+ limb_t prec, bf_flags_t flags, int rnd_mode);
+int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
+ bf_flags_t flags, int rnd_mode);
+int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
+ bf_flags_t flags, int rnd_mode);
+/* round to integer with infinite precision */
+int bf_rint(bf_t *r, int rnd_mode);
+int bf_round(bf_t *r, limb_t prec, bf_flags_t flags);
+int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a);
+int bf_sqrt(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
+slimb_t bf_get_exp_min(const bf_t *a);
+int bf_logic_or(bf_t *r, const bf_t *a, const bf_t *b);
+int bf_logic_xor(bf_t *r, const bf_t *a, const bf_t *b);
+int bf_logic_and(bf_t *r, const bf_t *a, const bf_t *b);
+
+/* additional flags for bf_atof */
+/* do not accept hex radix prefix (0x or 0X) if radix = 0 or radix = 16 */
+#define BF_ATOF_NO_HEX (1 << 16)
+/* accept binary (0b or 0B) or octal (0o or 0O) radix prefix if radix = 0 */
+#define BF_ATOF_BIN_OCT (1 << 17)
+/* Do not parse NaN or Inf */
+#define BF_ATOF_NO_NAN_INF (1 << 18)
+/* return the exponent separately */
+#define BF_ATOF_EXPONENT (1 << 19)
+
+int bf_atof(bf_t *a, const char *str, const char **pnext, int radix,
+ limb_t prec, bf_flags_t flags);
+/* this version accepts prec = BF_PREC_INF and returns the radix
+ exponent */
+int bf_atof2(bf_t *r, slimb_t *pexponent,
+ const char *str, const char **pnext, int radix,
+ limb_t prec, bf_flags_t flags);
+int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix,
+ slimb_t expn, limb_t prec, bf_flags_t flags);
+
+
+/* Conversion of floating point number to string. Return a null
+ terminated string or NULL if memory error. *plen contains its
+ length if plen != NULL. The exponent letter is "e" for base 10,
+ "p" for bases 2, 8, 16 with a binary exponent and "@" for the other
+ bases. */
+
+#define BF_FTOA_FORMAT_MASK (3 << 16)
+
+/* fixed format: prec significant digits rounded with (flags &
+ BF_RND_MASK). Exponential notation is used if too many zeros are
+ needed.*/
+#define BF_FTOA_FORMAT_FIXED (0 << 16)
+/* fractional format: prec digits after the decimal point rounded with
+ (flags & BF_RND_MASK) */
+#define BF_FTOA_FORMAT_FRAC (1 << 16)
+/* free format:
+
+ For binary radices with bf_ftoa() and for bfdec_ftoa(): use the minimum
+ number of digits to represent 'a'. The precision and the rounding
+ mode are ignored.
+
+ For the non binary radices with bf_ftoa(): use as many digits as
+ necessary so that bf_atof() return the same number when using
+ precision 'prec', rounding to nearest and the subnormal
+ configuration of 'flags'. The result is meaningful only if 'a' is
+ already rounded to 'prec' bits. If the subnormal flag is set, the
+ exponent in 'flags' must also be set to the desired exponent range.
+*/
+#define BF_FTOA_FORMAT_FREE (2 << 16)
+/* same as BF_FTOA_FORMAT_FREE but uses the minimum number of digits
+ (takes more computation time). Identical to BF_FTOA_FORMAT_FREE for
+ binary radices with bf_ftoa() and for bfdec_ftoa(). */
+#define BF_FTOA_FORMAT_FREE_MIN (3 << 16)
+
+/* force exponential notation for fixed or free format */
+#define BF_FTOA_FORCE_EXP (1 << 20)
+/* add 0x prefix for base 16, 0o prefix for base 8 or 0b prefix for
+ base 2 if non zero value */
+#define BF_FTOA_ADD_PREFIX (1 << 21)
+/* return "Infinity" instead of "Inf" and add a "+" for positive
+ exponents */
+#define BF_FTOA_JS_QUIRKS (1 << 22)
+
+char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec,
+ bf_flags_t flags);
+
+/* modulo 2^n instead of saturation. NaN and infinity return 0 */
+#define BF_GET_INT_MOD (1 << 0)
+int bf_get_int32(int *pres, const bf_t *a, int flags);
+int bf_get_int64(int64_t *pres, const bf_t *a, int flags);
+int bf_get_uint64(uint64_t *pres, const bf_t *a);
+
+/* the following functions are exported for testing only. */
+void mp_print_str(const char *str, const limb_t *tab, limb_t n);
+void bf_print_str(const char *str, const bf_t *a);
+int bf_resize(bf_t *r, limb_t len);
+int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len);
+int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags);
+int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k);
+slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv,
+ int is_ceil1);
+int mp_mul(bf_context_t *s, limb_t *result,
+ const limb_t *op1, limb_t op1_size,
+ const limb_t *op2, limb_t op2_size);
+limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2,
+ limb_t n, limb_t carry);
+limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n);
+int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n);
+int mp_recip(bf_context_t *s, limb_t *tabr, const limb_t *taba, limb_t n);
+limb_t bf_isqrt(limb_t a);
+
+/* transcendental functions */
+int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags);
+int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags);
+int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
+int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
+#define BF_POW_JS_QUIRKS (1 << 16) /* (+/-1)^(+/-Inf) = NaN, 1^NaN = NaN */
+int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags);
+int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
+int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
+int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
+int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
+int bf_atan2(bf_t *r, const bf_t *y, const bf_t *x,
+ limb_t prec, bf_flags_t flags);
+int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
+int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
+
+/* decimal floating point */
+
+static inline void bfdec_init(bf_context_t *s, bfdec_t *r)
+{
+ bf_init(s, (bf_t *)r);
+}
+static inline void bfdec_delete(bfdec_t *r)
+{
+ bf_delete((bf_t *)r);
+}
+
+static inline void bfdec_neg(bfdec_t *r)
+{
+ r->sign ^= 1;
+}
+
+static inline int bfdec_is_finite(const bfdec_t *a)
+{
+ return (a->expn < BF_EXP_INF);
+}
+
+static inline int bfdec_is_nan(const bfdec_t *a)
+{
+ return (a->expn == BF_EXP_NAN);
+}
+
+static inline int bfdec_is_zero(const bfdec_t *a)
+{
+ return (a->expn == BF_EXP_ZERO);
+}
+
+static inline void bfdec_memcpy(bfdec_t *r, const bfdec_t *a)
+{
+ bf_memcpy((bf_t *)r, (const bf_t *)a);
+}
+
+int bfdec_set_ui(bfdec_t *r, uint64_t a);
+int bfdec_set_si(bfdec_t *r, int64_t a);
+
+static inline void bfdec_set_nan(bfdec_t *r)
+{
+ bf_set_nan((bf_t *)r);
+}
+static inline void bfdec_set_zero(bfdec_t *r, int is_neg)
+{
+ bf_set_zero((bf_t *)r, is_neg);
+}
+static inline void bfdec_set_inf(bfdec_t *r, int is_neg)
+{
+ bf_set_inf((bf_t *)r, is_neg);
+}
+static inline int bfdec_set(bfdec_t *r, const bfdec_t *a)
+{
+ return bf_set((bf_t *)r, (bf_t *)a);
+}
+static inline void bfdec_move(bfdec_t *r, bfdec_t *a)
+{
+ bf_move((bf_t *)r, (bf_t *)a);
+}
+static inline int bfdec_cmpu(const bfdec_t *a, const bfdec_t *b)
+{
+ return bf_cmpu((const bf_t *)a, (const bf_t *)b);
+}
+static inline int bfdec_cmp_full(const bfdec_t *a, const bfdec_t *b)
+{
+ return bf_cmp_full((const bf_t *)a, (const bf_t *)b);
+}
+static inline int bfdec_cmp(const bfdec_t *a, const bfdec_t *b)
+{
+ return bf_cmp((const bf_t *)a, (const bf_t *)b);
+}
+static inline int bfdec_cmp_eq(const bfdec_t *a, const bfdec_t *b)
+{
+ return bfdec_cmp(a, b) == 0;
+}
+static inline int bfdec_cmp_le(const bfdec_t *a, const bfdec_t *b)
+{
+ return bfdec_cmp(a, b) <= 0;
+}
+static inline int bfdec_cmp_lt(const bfdec_t *a, const bfdec_t *b)
+{
+ return bfdec_cmp(a, b) < 0;
+}
+
+int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
+ bf_flags_t flags);
+int bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
+ bf_flags_t flags);
+int bfdec_add_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,
+ bf_flags_t flags);
+int bfdec_mul(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
+ bf_flags_t flags);
+int bfdec_mul_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,
+ bf_flags_t flags);
+int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
+ bf_flags_t flags);
+int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b,
+ limb_t prec, bf_flags_t flags, int rnd_mode);
+int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
+ bf_flags_t flags, int rnd_mode);
+int bfdec_rint(bfdec_t *r, int rnd_mode);
+int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags);
+int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags);
+int bfdec_get_int32(int *pres, const bfdec_t *a);
+int bfdec_pow_ui(bfdec_t *r, const bfdec_t *a, limb_t b);
+
+char *bfdec_ftoa(size_t *plen, const bfdec_t *a, limb_t prec, bf_flags_t flags);
+int bfdec_atof(bfdec_t *r, const char *str, const char **pnext,
+ limb_t prec, bf_flags_t flags);
+
+/* the following functions are exported for testing only. */
+extern const limb_t mp_pow_dec[LIMB_DIGITS + 1];
+void bfdec_print_str(const char *str, const bfdec_t *a);
+static inline int bfdec_resize(bfdec_t *r, limb_t len)
+{
+ return bf_resize((bf_t *)r, len);
+}
+int bfdec_normalize_and_round(bfdec_t *r, limb_t prec1, bf_flags_t flags);
+
+#ifdef __cplusplus
+} /* extern "C" { */
+#endif
+
+#endif /* LIBBF_H */
diff --git a/src/shared/quickjs/libregexp-opcode.h b/src/shared/quickjs/libregexp-opcode.h
index f90c23b34..f255e09f2 100644
--- a/src/shared/quickjs/libregexp-opcode.h
+++ b/src/shared/quickjs/libregexp-opcode.h
@@ -1,6 +1,6 @@
/*
* Regular Expression Engine
- *
+ *
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -50,8 +50,7 @@ DEF(range32, 3) /* variable length */
DEF(lookahead, 5)
DEF(negative_lookahead, 5)
DEF(push_char_pos, 1) /* push the character position on the stack */
-DEF(bne_char_pos, 5) /* pop one stack element and jump if equal to the character
- position */
+DEF(check_advance, 1) /* pop one stack element and check that it is different from the character position */
DEF(prev, 1) /* go to the previous char */
DEF(simple_greedy_quant, 17)
diff --git a/src/shared/quickjs/libregexp.c b/src/shared/quickjs/libregexp.c
index ad91f781a..4db042941 100644
--- a/src/shared/quickjs/libregexp.c
+++ b/src/shared/quickjs/libregexp.c
@@ -30,13 +30,11 @@
#include "cutils.h"
#include "libregexp.h"
+#include "libunicode.h"
/*
TODO:
- - Add full unicode canonicalize rules for character ranges (not
- really useful but needed for exact "ignorecase" compatibility).
-
- Add a lock step execution mode (=linear time execution guaranteed)
when the regular expression is "simple" i.e. no backreference nor
complicated lookahead. The opcodes are designed for this execution
@@ -69,7 +67,7 @@ typedef struct {
const uint8_t *buf_end;
const uint8_t *buf_start;
int re_flags;
- BOOL is_utf16;
+ BOOL is_unicode;
BOOL ignore_case;
BOOL dotall;
int capture_count;
@@ -103,6 +101,7 @@ static const REOpCode reopcode_info[REOP_COUNT] = {
#define RE_HEADER_FLAGS 0
#define RE_HEADER_CAPTURE_COUNT 1
#define RE_HEADER_STACK_SIZE 2
+#define RE_HEADER_BYTECODE_LEN 3
#define RE_HEADER_LEN 7
@@ -120,33 +119,6 @@ static int dbuf_insert(DynBuf *s, int pos, int len)
return 0;
}
-/* canonicalize with the specific JS regexp rules */
-static uint32_t lre_canonicalize(uint32_t c, BOOL is_utf16)
-{
- uint32_t res[LRE_CC_RES_LEN_MAX];
- int len;
- if (is_utf16) {
- if (likely(c < 128)) {
- if (c >= 'A' && c <= 'Z')
- c = c - 'A' + 'a';
- } else {
- lre_case_conv(res, c, 2);
- c = res[0];
- }
- } else {
- if (likely(c < 128)) {
- if (c >= 'a' && c <= 'z')
- c = c - 'a' + 'A';
- } else {
- /* legacy regexp: to upper case if single char >= 128 */
- len = lre_case_conv(res, c, FALSE);
- if (len == 1 && res[0] >= 128)
- c = res[0];
- }
- }
- return c;
-}
-
static const uint16_t char_range_d[] = {
1,
0x0030, 0x0039 + 1,
@@ -170,32 +142,6 @@ static const uint16_t char_range_s[] = {
0xFEFF, 0xFEFF + 1,
};
-BOOL lre_is_space(int c)
-{
- int i, n, low, high;
- n = (countof(char_range_s) - 1) / 2;
- for(i = 0; i < n; i++) {
- low = char_range_s[2 * i + 1];
- if (c < low)
- return FALSE;
- high = char_range_s[2 * i + 2];
- if (c < high)
- return TRUE;
- }
- return FALSE;
-}
-
-uint32_t const lre_id_start_table_ascii[4] = {
- /* $ A-Z _ a-z */
- 0x00000000, 0x00000010, 0x87FFFFFE, 0x07FFFFFE
-};
-
-uint32_t const lre_id_continue_table_ascii[4] = {
- /* $ 0-9 A-Z _ a-z */
- 0x00000000, 0x03FF0010, 0x87FFFFFE, 0x07FFFFFE
-};
-
-
static const uint16_t char_range_w[] = {
4,
0x0030, 0x0039 + 1,
@@ -215,7 +161,7 @@ typedef enum {
CHAR_RANGE_W,
} CharRangeEnum;
-static const uint16_t *char_range_table[] = {
+static const uint16_t * const char_range_table[] = {
char_range_d,
char_range_s,
char_range_w,
@@ -245,33 +191,8 @@ static int cr_init_char_range(REParseState *s, CharRange *cr, uint32_t c)
return -1;
}
-static int cr_canonicalize(CharRange *cr)
-{
- CharRange a;
- uint32_t pt[2];
- int i, ret;
-
- cr_init(&a, cr->mem_opaque, lre_realloc);
- pt[0] = 'a';
- pt[1] = 'z' + 1;
- ret = cr_op(&a, cr->points, cr->len, pt, 2, CR_OP_INTER);
- if (ret)
- goto fail;
- /* convert to upper case */
- /* XXX: the generic unicode case would be much more complicated
- and not really useful */
- for(i = 0; i < a.len; i++) {
- a.points[i] += 'A' - 'a';
- }
- /* Note: for simplicity we keep the lower case ranges */
- ret = cr_union1(cr, a.points, a.len);
- fail:
- cr_free(&a);
- return ret;
-}
-
#ifdef DUMP_REOP
-static MAYBE_UNUSED void lre_dump_bytecode(const uint8_t *buf,
+static __maybe_unused void lre_dump_bytecode(const uint8_t *buf,
int buf_len)
{
int pos, len, opcode, bc_len, re_flags, i;
@@ -279,16 +200,16 @@ static MAYBE_UNUSED void lre_dump_bytecode(const uint8_t *buf,
assert(buf_len >= RE_HEADER_LEN);
- re_flags= buf[0];
- bc_len = get_u32(buf + 3);
+ re_flags = lre_get_flags(buf);
+ bc_len = get_u32(buf + RE_HEADER_BYTECODE_LEN);
assert(bc_len + RE_HEADER_LEN <= buf_len);
printf("flags: 0x%x capture_count=%d stack_size=%d\n",
- re_flags, buf[1], buf[2]);
+ re_flags, buf[RE_HEADER_CAPTURE_COUNT], buf[RE_HEADER_STACK_SIZE]);
if (re_flags & LRE_FLAG_NAMED_GROUPS) {
const char *p;
p = (char *)buf + RE_HEADER_LEN + bc_len;
printf("named groups: ");
- for(i = 1; i < buf[1]; i++) {
+ for(i = 1; i < buf[RE_HEADER_CAPTURE_COUNT]; i++) {
if (i != 1)
printf(",");
printf("<%s>", p);
@@ -335,7 +256,6 @@ static MAYBE_UNUSED void lre_dump_bytecode(const uint8_t *buf,
case REOP_loop:
case REOP_lookahead:
case REOP_negative_lookahead:
- case REOP_bne_char_pos:
val = get_u32(buf + pos + 1);
val += (pos + 5);
printf(" %u", val);
@@ -550,7 +470,7 @@ int lre_parse_escape(const uint8_t **pp, int allow_utf16)
}
c = (c << 4) | h;
}
- if (c >= 0xd800 && c < 0xdc00 &&
+ if (is_hi_surrogate(c) &&
allow_utf16 == 2 && p[0] == '\\' && p[1] == 'u') {
/* convert an escaped surrogate pair into a
unicode char */
@@ -561,9 +481,9 @@ int lre_parse_escape(const uint8_t **pp, int allow_utf16)
break;
c1 = (c1 << 4) | h;
}
- if (i == 4 && c1 >= 0xdc00 && c1 < 0xe000) {
+ if (i == 4 && is_lo_surrogate(c1)) {
p += 6;
- c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
+ c = from_surrogate(c, c1);
}
}
}
@@ -752,10 +672,10 @@ static int get_class_atom(REParseState *s, CharRange *cr,
if ((c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(((c >= '0' && c <= '9') || c == '_') &&
- inclass && !s->is_utf16)) { /* Annex B.1.4 */
+ inclass && !s->is_unicode)) { /* Annex B.1.4 */
c &= 0x1f;
p++;
- } else if (s->is_utf16) {
+ } else if (s->is_unicode) {
goto invalid_escape;
} else {
/* otherwise return '\' and 'c' */
@@ -766,7 +686,7 @@ static int get_class_atom(REParseState *s, CharRange *cr,
#ifdef CONFIG_ALL_UNICODE
case 'p':
case 'P':
- if (s->is_utf16) {
+ if (s->is_unicode) {
if (parse_unicode_property(s, cr, &p, (c == 'P')))
return -1;
c = CLASS_RANGE_BASE;
@@ -776,14 +696,14 @@ static int get_class_atom(REParseState *s, CharRange *cr,
#endif
default:
p--;
- ret = lre_parse_escape(&p, s->is_utf16 * 2);
+ ret = lre_parse_escape(&p, s->is_unicode * 2);
if (ret >= 0) {
c = ret;
} else {
if (ret == -2 && *p != '\0' && strchr("^$\\.*+?()[]{}|/", *p)) {
/* always valid to escape these characters */
goto normal_char;
- } else if (s->is_utf16) {
+ } else if (s->is_unicode) {
invalid_escape:
return re_parse_error(s, "invalid escape sequence in regular expression");
} else {
@@ -805,7 +725,7 @@ static int get_class_atom(REParseState *s, CharRange *cr,
/* normal char */
if (c >= 128) {
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
- if ((unsigned)c > 0xffff && !s->is_utf16) {
+ if ((unsigned)c > 0xffff && !s->is_unicode) {
/* XXX: should handle non BMP-1 code points */
return re_parse_error(s, "malformed unicode char");
}
@@ -867,11 +787,13 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
cr_init(cr, s->opaque, lre_realloc);
p = *pp;
p++; /* skip '[' */
+
invert = FALSE;
if (*p == '^') {
p++;
invert = TRUE;
}
+
for(;;) {
if (*p == ']')
break;
@@ -881,7 +803,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
if (*p == '-' && p[1] != ']') {
const uint8_t *p0 = p + 1;
if (c1 >= CLASS_RANGE_BASE) {
- if (s->is_utf16) {
+ if (s->is_unicode) {
cr_free(cr1);
goto invalid_class_range;
}
@@ -893,7 +815,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
goto fail;
if (c2 >= CLASS_RANGE_BASE) {
cr_free(cr1);
- if (s->is_utf16) {
+ if (s->is_unicode) {
goto invalid_class_range;
}
/* Annex B: match '-' character */
@@ -922,7 +844,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
}
}
if (s->ignore_case) {
- if (cr_canonicalize(cr))
+ if (cr_regexp_canonicalize(cr, s->is_unicode))
goto memory_error;
}
if (invert) {
@@ -943,22 +865,17 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
}
/* Return:
- 1 if the opcodes in bc_buf[] always advance the character pointer.
- 0 if the character pointer may not be advanced.
- -1 if the code may depend on side effects of its previous execution (backreference)
+ - true if the opcodes may not advance the char pointer
+ - false if the opcodes always advance the char pointer
*/
-static int re_check_advance(const uint8_t *bc_buf, int bc_buf_len)
+static BOOL re_need_check_advance(const uint8_t *bc_buf, int bc_buf_len)
{
- int pos, opcode, ret, len, i;
- uint32_t val, last;
- BOOL has_back_reference;
- uint8_t capture_bitmap[CAPTURE_COUNT_MAX];
+ int pos, opcode, len;
+ uint32_t val;
+ BOOL ret;
- ret = -2; /* not known yet */
+ ret = TRUE;
pos = 0;
- has_back_reference = FALSE;
- memset(capture_bitmap, 0, sizeof(capture_bitmap));
-
while (pos < bc_buf_len) {
opcode = bc_buf[pos];
len = reopcode_info[opcode].size;
@@ -976,8 +893,7 @@ static int re_check_advance(const uint8_t *bc_buf, int bc_buf_len)
case REOP_dot:
case REOP_any:
simple_char:
- if (ret == -2)
- ret = 1;
+ ret = FALSE;
break;
case REOP_line_start:
case REOP_line_end:
@@ -991,41 +907,16 @@ static int re_check_advance(const uint8_t *bc_buf, int bc_buf_len)
break;
case REOP_save_start:
case REOP_save_end:
- val = bc_buf[pos + 1];
- capture_bitmap[val] |= 1;
- break;
case REOP_save_reset:
- {
- val = bc_buf[pos + 1];
- last = bc_buf[pos + 2];
- while (val < last)
- capture_bitmap[val++] |= 1;
- }
- break;
case REOP_back_reference:
case REOP_backward_back_reference:
- val = bc_buf[pos + 1];
- capture_bitmap[val] |= 2;
- has_back_reference = TRUE;
break;
default:
- /* safe behvior: we cannot predict the outcome */
- if (ret == -2)
- ret = 0;
- break;
+ /* safe behavior: we cannot predict the outcome */
+ return TRUE;
}
pos += len;
}
- if (has_back_reference) {
- /* check if there is back reference which references a capture
- made in the some code */
- for(i = 0; i < CAPTURE_COUNT_MAX; i++) {
- if (capture_bitmap[i] == 3)
- return -1;
- }
- }
- if (ret == -2)
- ret = 0;
return ret;
}
@@ -1071,11 +962,10 @@ static int re_is_simple_quantifier(const uint8_t *bc_buf, int bc_buf_len)
}
/* '*pp' is the first char after '<' */
-static int re_parse_group_name(char *buf, int buf_size,
- const uint8_t **pp, BOOL is_utf16)
+static int re_parse_group_name(char *buf, int buf_size, const uint8_t **pp)
{
- const uint8_t *p;
- uint32_t c;
+ const uint8_t *p, *p1;
+ uint32_t c, d;
char *q;
p = *pp;
@@ -1086,11 +976,18 @@ static int re_parse_group_name(char *buf, int buf_size,
p++;
if (*p != 'u')
return -1;
- c = lre_parse_escape(&p, is_utf16 * 2);
+ c = lre_parse_escape(&p, 2); // accept surrogate pairs
} else if (c == '>') {
break;
} else if (c >= 128) {
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
+ if (is_hi_surrogate(c)) {
+ d = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
+ if (is_lo_surrogate(d)) {
+ c = from_surrogate(c, d);
+ p = p1;
+ }
+ }
} else {
p++;
}
@@ -1140,8 +1037,7 @@ static int re_parse_captures(REParseState *s, int *phas_named_captures,
/* potential named capture */
if (capture_name) {
p += 3;
- if (re_parse_group_name(name, sizeof(name), &p,
- s->is_utf16) == 0) {
+ if (re_parse_group_name(name, sizeof(name), &p) == 0) {
if (!strcmp(name, capture_name))
return capture_index;
}
@@ -1196,9 +1092,10 @@ static int find_group_name(REParseState *s, const char *name)
size_t len, name_len;
int capture_index;
- name_len = strlen(name);
p = (char *)s->group_names.buf;
+ if (!p) return -1;
buf_end = (char *)s->group_names.buf + s->group_names.size;
+ name_len = strlen(name);
capture_index = 1;
while (p < buf_end) {
len = strlen(p);
@@ -1243,7 +1140,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
re_emit_op(s, REOP_prev);
break;
case '{':
- if (s->is_utf16) {
+ if (s->is_unicode) {
return re_parse_error(s, "syntax error");
} else if (!is_digit(p[1])) {
/* Annex B: we accept '{' not followed by digits as a
@@ -1295,7 +1192,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
lookahead:
/* Annex B allows lookahead to be used as an atom for
the quantifiers */
- if (!s->is_utf16 && !is_backward_lookahead) {
+ if (!s->is_unicode && !is_backward_lookahead) {
last_atom_start = s->byte_code.size;
last_capture_count = s->capture_count;
}
@@ -1314,7 +1211,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
} else if (p[2] == '<') {
p += 3;
if (re_parse_group_name(s->u.tmp_buf, sizeof(s->u.tmp_buf),
- &p, s->is_utf16)) {
+ &p)) {
return re_parse_error(s, "invalid group name");
}
if (find_group_name(s, s->u.tmp_buf) > 0) {
@@ -1371,15 +1268,15 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
/* annex B: we tolerate invalid group names in non
unicode mode if there is no named capture
definition */
- if (s->is_utf16 || re_has_named_captures(s))
+ if (s->is_unicode || re_has_named_captures(s))
return re_parse_error(s, "expecting group name");
else
goto parse_class_atom;
}
p1 += 3;
if (re_parse_group_name(s->u.tmp_buf, sizeof(s->u.tmp_buf),
- &p1, s->is_utf16)) {
- if (s->is_utf16 || re_has_named_captures(s))
+ &p1)) {
+ if (s->is_unicode || re_has_named_captures(s))
return re_parse_error(s, "invalid group name");
else
goto parse_class_atom;
@@ -1390,7 +1287,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
after (inefficient, but hopefully not common */
c = re_parse_captures(s, &dummy_res, s->u.tmp_buf);
if (c < 0) {
- if (s->is_utf16 || re_has_named_captures(s))
+ if (s->is_unicode || re_has_named_captures(s))
return re_parse_error(s, "group name not defined");
else
goto parse_class_atom;
@@ -1402,7 +1299,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
case '0':
p += 2;
c = 0;
- if (s->is_utf16) {
+ if (s->is_unicode) {
if (is_digit(*p)) {
return re_parse_error(s, "invalid decimal escape in regular expression");
}
@@ -1424,7 +1321,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
c = parse_digits(&p, FALSE);
if (c < 0 || (c >= s->capture_count && c >= re_count_captures(s))) {
- if (!s->is_utf16) {
+ if (!s->is_unicode) {
/* Annex B.1.4: accept legacy octal */
p = q;
if (*p <= '7') {
@@ -1466,13 +1363,13 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
break;
case ']':
case '}':
- if (s->is_utf16)
+ if (s->is_unicode)
return re_parse_error(s, "syntax error");
goto parse_class_atom;
default:
parse_class_atom:
c = get_class_atom(s, cr, &p, FALSE);
- if (c < 0)
+ if ((int)c < 0)
return -1;
normal_char:
last_atom_start = s->byte_code.size;
@@ -1488,7 +1385,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
return -1;
} else {
if (s->ignore_case)
- c = lre_canonicalize(c, s->is_utf16);
+ c = lre_canonicalize(c, s->is_unicode);
if (c <= 0xffff)
re_emit_op_u16(s, REOP_char, c);
else
@@ -1524,7 +1421,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
/* As an extension (see ES6 annex B), we accept '{' not
followed by digits as a normal atom */
if (!is_digit(p[1])) {
- if (s->is_utf16)
+ if (s->is_unicode)
goto invalid_quant_count;
break;
}
@@ -1543,7 +1440,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
quant_max = INT32_MAX; /* infinity */
}
}
- if (*p != '}' && !s->is_utf16) {
+ if (*p != '}' && !s->is_unicode) {
/* Annex B: normal atom if invalid '{' syntax */
p = p1;
break;
@@ -1591,8 +1488,12 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
if (dbuf_error(&s->byte_code))
goto out_of_memory;
- add_zero_advance_check = (re_check_advance(s->byte_code.buf + last_atom_start,
- s->byte_code.size - last_atom_start) == 0);
+ /* the spec tells that if there is no advance when
+ running the atom after the first quant_min times,
+ then there is no match. We remove this test when we
+ are sure the atom always advances the position. */
+ add_zero_advance_check = re_need_check_advance(s->byte_code.buf + last_atom_start,
+ s->byte_code.size - last_atom_start);
} else {
add_zero_advance_check = FALSE;
}
@@ -1612,38 +1513,34 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
}
if (quant_max == 0) {
s->byte_code.size = last_atom_start;
- } else if (quant_max == 1) {
- if (dbuf_insert(&s->byte_code, last_atom_start, 5))
- goto out_of_memory;
- s->byte_code.buf[last_atom_start] = REOP_split_goto_first +
- greedy;
- put_u32(s->byte_code.buf + last_atom_start + 1, len);
- } else if (quant_max == INT32_MAX) {
+ } else if (quant_max == 1 || quant_max == INT32_MAX) {
+ BOOL has_goto = (quant_max == INT32_MAX);
if (dbuf_insert(&s->byte_code, last_atom_start, 5 + add_zero_advance_check))
goto out_of_memory;
s->byte_code.buf[last_atom_start] = REOP_split_goto_first +
greedy;
put_u32(s->byte_code.buf + last_atom_start + 1,
- len + 5 + add_zero_advance_check);
+ len + 5 * has_goto + add_zero_advance_check * 2);
if (add_zero_advance_check) {
- /* avoid infinite loop by stoping the
- recursion if no advance was made in the
- atom (only works if the atom has no
- side effect) */
s->byte_code.buf[last_atom_start + 1 + 4] = REOP_push_char_pos;
- re_emit_goto(s, REOP_bne_char_pos, last_atom_start);
- } else {
- re_emit_goto(s, REOP_goto, last_atom_start);
+ re_emit_op(s, REOP_check_advance);
}
+ if (has_goto)
+ re_emit_goto(s, REOP_goto, last_atom_start);
} else {
- if (dbuf_insert(&s->byte_code, last_atom_start, 10))
+ if (dbuf_insert(&s->byte_code, last_atom_start, 10 + add_zero_advance_check))
goto out_of_memory;
pos = last_atom_start;
s->byte_code.buf[pos++] = REOP_push_i32;
put_u32(s->byte_code.buf + pos, quant_max);
pos += 4;
s->byte_code.buf[pos++] = REOP_split_goto_first + greedy;
- put_u32(s->byte_code.buf + pos, len + 5);
+ put_u32(s->byte_code.buf + pos, len + 5 + add_zero_advance_check * 2);
+ pos += 4;
+ if (add_zero_advance_check) {
+ s->byte_code.buf[pos++] = REOP_push_char_pos;
+ re_emit_op(s, REOP_check_advance);
+ }
re_emit_goto(s, REOP_loop, last_atom_start + 5);
re_emit_op(s, REOP_drop);
}
@@ -1667,22 +1564,25 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
if (quant_max == INT32_MAX) {
pos = s->byte_code.size;
re_emit_op_u32(s, REOP_split_goto_first + greedy,
- len + 5 + add_zero_advance_check);
+ len + 5 + add_zero_advance_check * 2);
if (add_zero_advance_check)
re_emit_op(s, REOP_push_char_pos);
/* copy the atom */
dbuf_put_self(&s->byte_code, last_atom_start, len);
if (add_zero_advance_check)
- re_emit_goto(s, REOP_bne_char_pos, pos);
- else
- re_emit_goto(s, REOP_goto, pos);
+ re_emit_op(s, REOP_check_advance);
+ re_emit_goto(s, REOP_goto, pos);
} else if (quant_max > quant_min) {
re_emit_op_u32(s, REOP_push_i32, quant_max - quant_min);
pos = s->byte_code.size;
- re_emit_op_u32(s, REOP_split_goto_first + greedy, len + 5);
+ re_emit_op_u32(s, REOP_split_goto_first + greedy,
+ len + 5 + add_zero_advance_check * 2);
+ if (add_zero_advance_check)
+ re_emit_op(s, REOP_push_char_pos);
/* copy the atom */
dbuf_put_self(&s->byte_code, last_atom_start, len);
-
+ if (add_zero_advance_check)
+ re_emit_op(s, REOP_check_advance);
re_emit_goto(s, REOP_loop, pos);
re_emit_op(s, REOP_drop);
}
@@ -1796,7 +1696,7 @@ static int compute_stack_size(const uint8_t *bc_buf, int bc_buf_len)
}
break;
case REOP_drop:
- case REOP_bne_char_pos:
+ case REOP_check_advance:
assert(stack_size > 0);
stack_size--;
break;
@@ -1832,7 +1732,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
s->buf_end = s->buf_ptr + buf_len;
s->buf_start = s->buf_ptr;
s->re_flags = re_flags;
- s->is_utf16 = ((re_flags & LRE_FLAG_UTF16) != 0);
+ s->is_unicode = ((re_flags & LRE_FLAG_UNICODE) != 0);
is_sticky = ((re_flags & LRE_FLAG_STICKY) != 0);
s->ignore_case = ((re_flags & LRE_FLAG_IGNORECASE) != 0);
s->dotall = ((re_flags & LRE_FLAG_DOTALL) != 0);
@@ -1890,7 +1790,8 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
s->byte_code.buf[RE_HEADER_CAPTURE_COUNT] = s->capture_count;
s->byte_code.buf[RE_HEADER_STACK_SIZE] = stack_size;
- put_u32(s->byte_code.buf + 3, s->byte_code.size - RE_HEADER_LEN);
+ put_u32(s->byte_code.buf + RE_HEADER_BYTECODE_LEN,
+ s->byte_code.size - RE_HEADER_LEN);
/* add the named groups if needed */
if (s->group_names.size > (s->capture_count - 1)) {
@@ -1921,93 +1822,86 @@ static BOOL is_word_char(uint32_t c)
(c == '_'));
}
-#define GET_CHAR(c, cptr, cbuf_end) \
+#define GET_CHAR(c, cptr, cbuf_end, cbuf_type) \
do { \
if (cbuf_type == 0) { \
- (c) = *(cptr)++; \
+ c = *cptr++; \
} else { \
- uint32_t __c1; \
- (c) = *(uint16_t *)(cptr); \
- (cptr) += 2; \
- if ((c) >= 0xd800 && (c) < 0xdc00 && \
- cbuf_type == 2 && (cptr) < (cbuf_end)) { \
- __c1 = *(uint16_t *)(cptr); \
- if (__c1 >= 0xdc00 && __c1 < 0xe000) { \
- (c) = ((((c) & 0x3ff) << 10) | (__c1 & 0x3ff)) + 0x10000; \
- (cptr) += 2; \
+ const uint16_t *_p = (const uint16_t *)cptr; \
+ const uint16_t *_end = (const uint16_t *)cbuf_end; \
+ c = *_p++; \
+ if (is_hi_surrogate(c) && cbuf_type == 2) { \
+ if (_p < _end && is_lo_surrogate(*_p)) { \
+ c = from_surrogate(c, *_p++); \
} \
} \
+ cptr = (const void *)_p; \
} \
} while (0)
-#define PEEK_CHAR(c, cptr, cbuf_end) \
- do { \
- if (cbuf_type == 0) { \
- (c) = (cptr)[0]; \
- } else { \
- uint32_t __c1; \
- (c) = ((uint16_t *)(cptr))[0]; \
- if ((c) >= 0xd800 && (c) < 0xdc00 && \
- cbuf_type == 2 && ((cptr) + 2) < (cbuf_end)) { \
- __c1 = ((uint16_t *)(cptr))[1]; \
- if (__c1 >= 0xdc00 && __c1 < 0xe000) { \
- (c) = ((((c) & 0x3ff) << 10) | (__c1 & 0x3ff)) + 0x10000; \
+#define PEEK_CHAR(c, cptr, cbuf_end, cbuf_type) \
+ do { \
+ if (cbuf_type == 0) { \
+ c = cptr[0]; \
+ } else { \
+ const uint16_t *_p = (const uint16_t *)cptr; \
+ const uint16_t *_end = (const uint16_t *)cbuf_end; \
+ c = *_p++; \
+ if (is_hi_surrogate(c) && cbuf_type == 2) { \
+ if (_p < _end && is_lo_surrogate(*_p)) { \
+ c = from_surrogate(c, *_p); \
} \
} \
- } \
+ } \
} while (0)
-#define PEEK_PREV_CHAR(c, cptr, cbuf_start) \
- do { \
- if (cbuf_type == 0) { \
- (c) = (cptr)[-1]; \
- } else { \
- uint32_t __c1; \
- (c) = ((uint16_t *)(cptr))[-1]; \
- if ((c) >= 0xdc00 && (c) < 0xe000 && \
- cbuf_type == 2 && ((cptr) - 4) >= (cbuf_start)) { \
- __c1 = ((uint16_t *)(cptr))[-2]; \
- if (__c1 >= 0xd800 && __c1 < 0xdc00 ) { \
- (c) = (((__c1 & 0x3ff) << 10) | ((c) & 0x3ff)) + 0x10000; \
+#define PEEK_PREV_CHAR(c, cptr, cbuf_start, cbuf_type) \
+ do { \
+ if (cbuf_type == 0) { \
+ c = cptr[-1]; \
+ } else { \
+ const uint16_t *_p = (const uint16_t *)cptr - 1; \
+ const uint16_t *_start = (const uint16_t *)cbuf_start; \
+ c = *_p; \
+ if (is_lo_surrogate(c) && cbuf_type == 2) { \
+ if (_p > _start && is_hi_surrogate(_p[-1])) { \
+ c = from_surrogate(*--_p, c); \
} \
} \
} \
} while (0)
-#define GET_PREV_CHAR(c, cptr, cbuf_start) \
- do { \
- if (cbuf_type == 0) { \
- (cptr)--; \
- (c) = (cptr)[0]; \
- } else { \
- uint32_t __c1; \
- (cptr) -= 2; \
- (c) = ((uint16_t *)(cptr))[0]; \
- if ((c) >= 0xdc00 && (c) < 0xe000 && \
- cbuf_type == 2 && (cptr) > (cbuf_start)) { \
- __c1 = ((uint16_t *)(cptr))[-1]; \
- if (__c1 >= 0xd800 && __c1 < 0xdc00 ) { \
- (cptr) -= 2; \
- (c) = (((__c1 & 0x3ff) << 10) | ((c) & 0x3ff)) + 0x10000; \
+#define GET_PREV_CHAR(c, cptr, cbuf_start, cbuf_type) \
+ do { \
+ if (cbuf_type == 0) { \
+ cptr--; \
+ c = cptr[0]; \
+ } else { \
+ const uint16_t *_p = (const uint16_t *)cptr - 1; \
+ const uint16_t *_start = (const uint16_t *)cbuf_start; \
+ c = *_p; \
+ if (is_lo_surrogate(c) && cbuf_type == 2) { \
+ if (_p > _start && is_hi_surrogate(_p[-1])) { \
+ c = from_surrogate(*--_p, c); \
} \
} \
+ cptr = (const void *)_p; \
} \
} while (0)
-#define PREV_CHAR(cptr, cbuf_start) \
- do { \
- if (cbuf_type == 0) { \
- (cptr)--; \
- } else { \
- (cptr) -= 2; \
- if (cbuf_type == 2) { \
- c = ((uint16_t *)(cptr))[0]; \
- if (c >= 0xdc00 && c < 0xe000 && (cptr) > (cbuf_start)) { \
- c = ((uint16_t *)(cptr))[-1]; \
- if (c >= 0xd800 && c < 0xdc00) \
- (cptr) -= 2; \
+#define PREV_CHAR(cptr, cbuf_start, cbuf_type) \
+ do { \
+ if (cbuf_type == 0) { \
+ cptr--; \
+ } else { \
+ const uint16_t *_p = (const uint16_t *)cptr - 1; \
+ const uint16_t *_start = (const uint16_t *)cbuf_start; \
+ if (is_lo_surrogate(*_p) && cbuf_type == 2) { \
+ if (_p > _start && is_hi_surrogate(_p[-1])) { \
+ --_p; \
} \
} \
+ cptr = (const void *)_p; \
} \
} while (0)
@@ -2038,7 +1932,7 @@ typedef struct {
int stack_size_max;
BOOL multi_line;
BOOL ignore_case;
- BOOL is_utf16;
+ BOOL is_unicode;
void *opaque; /* used for stack overflow check */
size_t state_size;
@@ -2049,7 +1943,7 @@ typedef struct {
static int push_state(REExecContext *s,
uint8_t **capture,
- const StackInt *stack, size_t stack_len,
+ StackInt *stack, size_t stack_len,
const uint8_t *pc, const uint8_t *cptr,
REExecStateEnum type, size_t count)
{
@@ -2147,7 +2041,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
/* go backward */
char_count = get_u32(pc + 12);
for(i = 0; i < char_count; i++) {
- PREV_CHAR(cptr, s->cbuf);
+ PREV_CHAR(cptr, s->cbuf, cbuf_type);
}
pc = (pc + 16) + (int)get_u32(pc);
rs->cptr = cptr;
@@ -2182,9 +2076,9 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
test_char:
if (cptr >= cbuf_end)
goto no_match;
- GET_CHAR(c, cptr, cbuf_end);
+ GET_CHAR(c, cptr, cbuf_end, cbuf_type);
if (s->ignore_case) {
- c = lre_canonicalize(c, s->is_utf16);
+ c = lre_canonicalize(c, s->is_unicode);
}
if (val != c)
goto no_match;
@@ -2229,7 +2123,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
break;
if (!s->multi_line)
goto no_match;
- PEEK_PREV_CHAR(c, cptr, s->cbuf);
+ PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type);
if (!is_line_terminator(c))
goto no_match;
break;
@@ -2238,21 +2132,21 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
break;
if (!s->multi_line)
goto no_match;
- PEEK_CHAR(c, cptr, cbuf_end);
+ PEEK_CHAR(c, cptr, cbuf_end, cbuf_type);
if (!is_line_terminator(c))
goto no_match;
break;
case REOP_dot:
if (cptr == cbuf_end)
goto no_match;
- GET_CHAR(c, cptr, cbuf_end);
+ GET_CHAR(c, cptr, cbuf_end, cbuf_type);
if (is_line_terminator(c))
goto no_match;
break;
case REOP_any:
if (cptr == cbuf_end)
goto no_match;
- GET_CHAR(c, cptr, cbuf_end);
+ GET_CHAR(c, cptr, cbuf_end, cbuf_type);
break;
case REOP_save_start:
case REOP_save_end:
@@ -2292,11 +2186,9 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
case REOP_push_char_pos:
stack[stack_len++] = (uintptr_t)cptr;
break;
- case REOP_bne_char_pos:
- val = get_u32(pc);
- pc += 4;
- if (stack[--stack_len] != (uintptr_t)cptr)
- pc += (int)val;
+ case REOP_check_advance:
+ if (stack[--stack_len] == (uintptr_t)cptr)
+ goto no_match;
break;
case REOP_word_boundary:
case REOP_not_word_boundary:
@@ -2306,14 +2198,14 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
if (cptr == s->cbuf) {
v1 = FALSE;
} else {
- PEEK_PREV_CHAR(c, cptr, s->cbuf);
+ PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type);
v1 = is_word_char(c);
}
/* current char */
if (cptr >= cbuf_end) {
v2 = FALSE;
} else {
- PEEK_CHAR(c, cptr, cbuf_end);
+ PEEK_CHAR(c, cptr, cbuf_end, cbuf_type);
v2 = is_word_char(c);
}
if (v1 ^ v2 ^ (REOP_not_word_boundary - opcode))
@@ -2338,11 +2230,11 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
while (cptr1 < cptr1_end) {
if (cptr >= cbuf_end)
goto no_match;
- GET_CHAR(c1, cptr1, cptr1_end);
- GET_CHAR(c2, cptr, cbuf_end);
+ GET_CHAR(c1, cptr1, cptr1_end, cbuf_type);
+ GET_CHAR(c2, cptr, cbuf_end, cbuf_type);
if (s->ignore_case) {
- c1 = lre_canonicalize(c1, s->is_utf16);
- c2 = lre_canonicalize(c2, s->is_utf16);
+ c1 = lre_canonicalize(c1, s->is_unicode);
+ c2 = lre_canonicalize(c2, s->is_unicode);
}
if (c1 != c2)
goto no_match;
@@ -2352,11 +2244,11 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
while (cptr1 > cptr1_start) {
if (cptr == s->cbuf)
goto no_match;
- GET_PREV_CHAR(c1, cptr1, cptr1_start);
- GET_PREV_CHAR(c2, cptr, s->cbuf);
+ GET_PREV_CHAR(c1, cptr1, cptr1_start, cbuf_type);
+ GET_PREV_CHAR(c2, cptr, s->cbuf, cbuf_type);
if (s->ignore_case) {
- c1 = lre_canonicalize(c1, s->is_utf16);
- c2 = lre_canonicalize(c2, s->is_utf16);
+ c1 = lre_canonicalize(c1, s->is_unicode);
+ c2 = lre_canonicalize(c2, s->is_unicode);
}
if (c1 != c2)
goto no_match;
@@ -2373,9 +2265,9 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
pc += 2;
if (cptr >= cbuf_end)
goto no_match;
- GET_CHAR(c, cptr, cbuf_end);
+ GET_CHAR(c, cptr, cbuf_end, cbuf_type);
if (s->ignore_case) {
- c = lre_canonicalize(c, s->is_utf16);
+ c = lre_canonicalize(c, s->is_unicode);
}
idx_min = 0;
low = get_u16(pc + 0 * 4);
@@ -2413,9 +2305,9 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
pc += 2;
if (cptr >= cbuf_end)
goto no_match;
- GET_CHAR(c, cptr, cbuf_end);
+ GET_CHAR(c, cptr, cbuf_end, cbuf_type);
if (s->ignore_case) {
- c = lre_canonicalize(c, s->is_utf16);
+ c = lre_canonicalize(c, s->is_unicode);
}
idx_min = 0;
low = get_u32(pc + 0 * 8);
@@ -2445,7 +2337,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
/* go to the previous char */
if (cptr == s->cbuf)
goto no_match;
- PREV_CHAR(cptr, s->cbuf);
+ PREV_CHAR(cptr, s->cbuf, cbuf_type);
break;
case REOP_simple_greedy_quant:
{
@@ -2504,16 +2396,16 @@ int lre_exec(uint8_t **capture,
int re_flags, i, alloca_size, ret;
StackInt *stack_buf;
- re_flags = bc_buf[RE_HEADER_FLAGS];
+ re_flags = lre_get_flags(bc_buf);
s->multi_line = (re_flags & LRE_FLAG_MULTILINE) != 0;
s->ignore_case = (re_flags & LRE_FLAG_IGNORECASE) != 0;
- s->is_utf16 = (re_flags & LRE_FLAG_UTF16) != 0;
+ s->is_unicode = (re_flags & LRE_FLAG_UNICODE) != 0;
s->capture_count = bc_buf[RE_HEADER_CAPTURE_COUNT];
s->stack_size_max = bc_buf[RE_HEADER_STACK_SIZE];
s->cbuf = cbuf;
s->cbuf_end = cbuf + (clen << cbuf_type);
s->cbuf_type = cbuf_type;
- if (s->cbuf_type == 1 && s->is_utf16)
+ if (s->cbuf_type == 1 && s->is_unicode)
s->cbuf_type = 2;
s->opaque = opaque;
@@ -2551,8 +2443,8 @@ const char *lre_get_groupnames(const uint8_t *bc_buf)
uint32_t re_bytecode_len;
if ((lre_get_flags(bc_buf) & LRE_FLAG_NAMED_GROUPS) == 0)
return NULL;
- re_bytecode_len = get_u32(bc_buf + 3);
- return (const char *)(bc_buf + 7 + re_bytecode_len);
+ re_bytecode_len = get_u32(bc_buf + RE_HEADER_BYTECODE_LEN);
+ return (const char *)(bc_buf + RE_HEADER_LEN + re_bytecode_len);
}
#ifdef TEST
@@ -2569,25 +2461,26 @@ void *lre_realloc(void *opaque, void *ptr, size_t size)
int main(int argc, char **argv)
{
- int len, ret, i;
+ int len, flags, ret, i;
uint8_t *bc;
char error_msg[64];
uint8_t *capture[CAPTURE_COUNT_MAX * 2];
const char *input;
int input_len, capture_count;
- if (argc < 3) {
- printf("usage: %s regexp input\n", argv[0]);
- exit(1);
+ if (argc < 4) {
+ printf("usage: %s regexp flags input\n", argv[0]);
+ return 1;
}
+ flags = atoi(argv[2]);
bc = lre_compile(&len, error_msg, sizeof(error_msg), argv[1],
- strlen(argv[1]), 0, NULL);
+ strlen(argv[1]), flags, NULL);
if (!bc) {
fprintf(stderr, "error: %s\n", error_msg);
exit(1);
}
- input = argv[2];
+ input = argv[3];
input_len = strlen(input);
ret = lre_exec(capture, bc, (uint8_t *)input, 0, input_len, 0, NULL);
diff --git a/src/shared/quickjs/libregexp.h b/src/shared/quickjs/libregexp.h
index 9aedb7e93..7af7ece0f 100644
--- a/src/shared/quickjs/libregexp.h
+++ b/src/shared/quickjs/libregexp.h
@@ -1,6 +1,6 @@
/*
* Regular Expression Engine
- *
+ *
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -25,18 +25,15 @@
#define LIBREGEXP_H
#include <stddef.h>
-
-#include "libunicode.h"
-
-#define LRE_BOOL int /* for documentation purposes */
+#include <stdint.h>
#define LRE_FLAG_GLOBAL (1 << 0)
#define LRE_FLAG_IGNORECASE (1 << 1)
#define LRE_FLAG_MULTILINE (1 << 2)
#define LRE_FLAG_DOTALL (1 << 3)
-#define LRE_FLAG_UTF16 (1 << 4)
+#define LRE_FLAG_UNICODE (1 << 4)
#define LRE_FLAG_STICKY (1 << 5)
-
+#define LRE_FLAG_INDICES (1 << 6) /* Unused by libregexp, just recorded. */
#define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */
uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
@@ -50,43 +47,9 @@ int lre_exec(uint8_t **capture,
int cbuf_type, void *opaque);
int lre_parse_escape(const uint8_t **pp, int allow_utf16);
-LRE_BOOL lre_is_space(int c);
-/* must be provided by the user */
-LRE_BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size);
+/* must be provided by the user, return non zero if overflow */
+int lre_check_stack_overflow(void *opaque, size_t alloca_size);
void *lre_realloc(void *opaque, void *ptr, size_t size);
-/* JS identifier test */
-extern uint32_t const lre_id_start_table_ascii[4];
-extern uint32_t const lre_id_continue_table_ascii[4];
-
-static inline int lre_js_is_ident_first(int c)
-{
- if ((uint32_t)c < 128) {
- return (lre_id_start_table_ascii[c >> 5] >> (c & 31)) & 1;
- } else {
-#ifdef CONFIG_ALL_UNICODE
- return lre_is_id_start(c);
-#else
- return !lre_is_space(c);
-#endif
- }
-}
-
-static inline int lre_js_is_ident_next(int c)
-{
- if ((uint32_t)c < 128) {
- return (lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1;
- } else {
- /* ZWNJ and ZWJ are accepted in identifiers */
-#ifdef CONFIG_ALL_UNICODE
- return lre_is_id_continue(c) || c == 0x200C || c == 0x200D;
-#else
- return !lre_is_space(c) || c == 0x200C || c == 0x200D;
-#endif
- }
-}
-
-#undef LRE_BOOL
-
#endif /* LIBREGEXP_H */
diff --git a/src/shared/quickjs/libunicode-table.h b/src/shared/quickjs/libunicode-table.h
index 1727525fb..72d495e78 100644
--- a/src/shared/quickjs/libunicode-table.h
+++ b/src/shared/quickjs/libunicode-table.h
@@ -160,40 +160,45 @@ static const uint16_t case_conv_ext[58] = {
0x006b, 0x00e5,
};
-static const uint8_t unicode_prop_Cased1_table[188] = {
+static const uint8_t unicode_prop_Cased1_table[196] = {
0x40, 0xa9, 0x80, 0x8e, 0x80, 0xfc, 0x80, 0xd3,
0x80, 0x8c, 0x80, 0x8d, 0x81, 0x8d, 0x02, 0x80,
0xe1, 0x80, 0x91, 0x85, 0x9a, 0x01, 0x00, 0x01,
0x11, 0x00, 0x01, 0x04, 0x08, 0x01, 0x08, 0x30,
0x08, 0x01, 0x15, 0x20, 0x00, 0x39, 0x99, 0x31,
0x9d, 0x84, 0x40, 0x94, 0x80, 0xd6, 0x82, 0xa6,
- 0x80, 0x41, 0x62, 0x80, 0xa6, 0x80, 0x57, 0x76,
- 0xf8, 0x02, 0x80, 0x8f, 0x80, 0xb0, 0x40, 0xdb,
- 0x08, 0x80, 0x41, 0xd0, 0x80, 0x8c, 0x80, 0x8f,
- 0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00, 0x14, 0x28,
- 0x10, 0x11, 0x02, 0x01, 0x18, 0x0b, 0x24, 0x4b,
- 0x26, 0x01, 0x01, 0x86, 0xe5, 0x80, 0x60, 0x79,
- 0xb6, 0x81, 0x40, 0x91, 0x81, 0xbd, 0x88, 0x94,
- 0x05, 0x80, 0x98, 0x80, 0xa2, 0x00, 0x80, 0xa1,
- 0x82, 0x43, 0x34, 0xa2, 0x06, 0x80, 0x8c, 0x60,
- 0x5c, 0x16, 0x01, 0x10, 0xa9, 0x80, 0x88, 0x60,
- 0xcc, 0x44, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09,
- 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03,
- 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16,
- 0x80, 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80,
+ 0x80, 0x41, 0x62, 0x80, 0xa6, 0x80, 0x4b, 0x72,
+ 0x80, 0x4c, 0x02, 0xf8, 0x02, 0x80, 0x8f, 0x80,
+ 0xb0, 0x40, 0xdb, 0x08, 0x80, 0x41, 0xd0, 0x80,
+ 0x8c, 0x80, 0x8f, 0x8c, 0xe4, 0x03, 0x01, 0x89,
+ 0x00, 0x14, 0x28, 0x10, 0x11, 0x02, 0x01, 0x18,
+ 0x0b, 0x24, 0x4b, 0x26, 0x01, 0x01, 0x86, 0xe5,
+ 0x80, 0x60, 0x79, 0xb6, 0x81, 0x40, 0x91, 0x81,
+ 0xbd, 0x88, 0x94, 0x05, 0x80, 0x98, 0x80, 0xa2,
+ 0x00, 0x80, 0x9b, 0x12, 0x82, 0x43, 0x34, 0xa2,
+ 0x06, 0x80, 0x8d, 0x60, 0x5c, 0x15, 0x01, 0x10,
+ 0xa9, 0x80, 0x88, 0x60, 0xcc, 0x44, 0xd4, 0x80,
+ 0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80, 0x8b, 0x00,
+ 0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06, 0x80, 0x9b,
+ 0x03, 0x04, 0x00, 0x16, 0x80, 0x41, 0x53, 0x81,
+ 0x98, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80,
0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80,
- 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07,
- 0x47, 0x33, 0x89, 0x80, 0x93, 0x52, 0x10, 0x99,
+ 0x9e, 0x80, 0x98, 0x07, 0x47, 0x33, 0x89, 0x80,
+ 0x93, 0x2d, 0x41, 0x04, 0xbd, 0x50, 0xc1, 0x99,
0x85, 0x99, 0x85, 0x99,
};
-static const uint8_t unicode_prop_Cased1_index[18] = {
- 0xb9, 0x02, 0xe0, 0xa0, 0x1e, 0x40, 0x9e, 0xa6,
- 0x40, 0x55, 0xd4, 0x61, 0xfb, 0xd6, 0x21, 0x8a,
- 0xf1, 0x01,
+static const uint8_t unicode_prop_Cased1_index[21] = {
+ 0xb9, 0x02, 0xe0, // 002B9 at 39
+ 0xc0, 0x1d, 0x20, // 01DC0 at 65
+ 0xe5, 0x2c, 0x20, // 02CE5 at 97
+ 0xb1, 0x07, 0x21, // 107B1 at 129
+ 0xc1, 0xd6, 0x21, // 1D6C1 at 161
+ 0x4a, 0xf1, 0x01, // 1F14A at 192
+ 0x8a, 0xf1, 0x01, // 1F18A at 224 (upper bound)
};
-static const uint8_t unicode_prop_Case_Ignorable_table[720] = {
+static const uint8_t unicode_prop_Case_Ignorable_table[737] = {
0xa6, 0x05, 0x80, 0x8a, 0x80, 0xa2, 0x00, 0x80,
0xc6, 0x03, 0x00, 0x03, 0x01, 0x81, 0x41, 0xf6,
0x40, 0xbf, 0x19, 0x18, 0x88, 0x08, 0x80, 0x40,
@@ -215,7 +220,7 @@ static const uint8_t unicode_prop_Case_Ignorable_table[720] = {
0x01, 0x05, 0x04, 0x81, 0x93, 0x81, 0x9b, 0x81,
0xb8, 0x0b, 0x1f, 0x80, 0x93, 0x81, 0x9c, 0x80,
0xc7, 0x06, 0x10, 0x80, 0xd9, 0x01, 0x86, 0x8a,
- 0x88, 0xe1, 0x01, 0x88, 0x88, 0x00, 0x85, 0xc9,
+ 0x88, 0xe1, 0x01, 0x88, 0x88, 0x00, 0x86, 0xc8,
0x81, 0x9a, 0x00, 0x00, 0x80, 0xb6, 0x8d, 0x04,
0x01, 0x84, 0x8a, 0x80, 0xa3, 0x88, 0x80, 0xe5,
0x18, 0x28, 0x09, 0x81, 0x98, 0x0b, 0x82, 0x8f,
@@ -256,49 +261,66 @@ static const uint8_t unicode_prop_Case_Ignorable_table[720] = {
0x80, 0x40, 0x94, 0x84, 0x44, 0x04, 0x28, 0xa9,
0x80, 0x88, 0x42, 0x45, 0x10, 0x0c, 0x83, 0xa7,
0x13, 0x80, 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x83,
- 0x41, 0x82, 0x81, 0x40, 0x98, 0x8a, 0xb0, 0x83,
- 0xfa, 0x80, 0xb5, 0x8e, 0xa8, 0x01, 0x81, 0x89,
- 0x82, 0xb0, 0x19, 0x09, 0x03, 0x80, 0x89, 0x80,
- 0xb1, 0x82, 0xa3, 0x20, 0x87, 0xbd, 0x80, 0x8b,
- 0x81, 0xb3, 0x88, 0x89, 0x19, 0x80, 0xde, 0x11,
- 0x00, 0x0d, 0x80, 0x40, 0x9f, 0x02, 0x87, 0x94,
- 0x81, 0xb8, 0x0a, 0x80, 0xa4, 0x32, 0x84, 0x40,
- 0xc2, 0x39, 0x10, 0x80, 0x96, 0x80, 0xd3, 0x28,
- 0x03, 0x08, 0x81, 0x40, 0xed, 0x1d, 0x08, 0x81,
- 0x9a, 0x81, 0xd4, 0x39, 0x00, 0x81, 0xe9, 0x00,
- 0x01, 0x28, 0x80, 0xe4, 0x11, 0x18, 0x84, 0x41,
- 0x02, 0x88, 0x01, 0x40, 0xff, 0x08, 0x03, 0x80,
- 0x40, 0x8f, 0x19, 0x0b, 0x80, 0x9f, 0x89, 0xa7,
- 0x29, 0x1f, 0x80, 0x88, 0x29, 0x82, 0xad, 0x8c,
- 0x01, 0x41, 0x95, 0x30, 0x28, 0x80, 0xd1, 0x95,
- 0x0e, 0x01, 0x01, 0xf9, 0x2a, 0x00, 0x08, 0x30,
- 0x80, 0xc7, 0x0a, 0x00, 0x80, 0x41, 0x5a, 0x81,
- 0x55, 0x3a, 0x88, 0x60, 0x36, 0xb6, 0x84, 0xba,
- 0x86, 0x88, 0x83, 0x44, 0x0a, 0x80, 0xbe, 0x90,
- 0xbf, 0x08, 0x81, 0x60, 0x40, 0x0a, 0x18, 0x30,
- 0x81, 0x4c, 0x9d, 0x08, 0x83, 0x52, 0x5b, 0xad,
- 0x81, 0x96, 0x42, 0x1f, 0x82, 0x88, 0x8f, 0x0e,
- 0x9d, 0x83, 0x40, 0x93, 0x82, 0x47, 0xba, 0xb6,
- 0x83, 0xb1, 0x38, 0x8d, 0x80, 0x95, 0x20, 0x8e,
- 0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04, 0x41,
- 0x04, 0x8d, 0x41, 0x6f, 0x80, 0xbc, 0x83, 0x45,
- 0xdf, 0x86, 0xec, 0x87, 0x4a, 0xae, 0x84, 0x6c,
- 0x0c, 0x00, 0x80, 0x9d, 0xdf, 0xff, 0x40, 0xef,
+ 0x41, 0x82, 0x81, 0xcf, 0x82, 0xc5, 0x8a, 0xb0,
+ 0x83, 0xfa, 0x80, 0xb5, 0x8e, 0xa8, 0x01, 0x81,
+ 0x89, 0x82, 0xb0, 0x19, 0x09, 0x03, 0x80, 0x89,
+ 0x80, 0xb1, 0x82, 0xa3, 0x20, 0x87, 0xbd, 0x80,
+ 0x8b, 0x81, 0xb3, 0x88, 0x89, 0x19, 0x80, 0xde,
+ 0x11, 0x00, 0x0d, 0x01, 0x80, 0x40, 0x9c, 0x02,
+ 0x87, 0x94, 0x81, 0xb8, 0x0a, 0x80, 0xa4, 0x32,
+ 0x84, 0x40, 0xc2, 0x39, 0x10, 0x80, 0x96, 0x80,
+ 0xd3, 0x28, 0x03, 0x08, 0x81, 0x40, 0xed, 0x1d,
+ 0x08, 0x81, 0x9a, 0x81, 0xd4, 0x39, 0x00, 0x81,
+ 0xe9, 0x00, 0x01, 0x28, 0x80, 0xe4, 0x11, 0x18,
+ 0x84, 0x41, 0x02, 0x88, 0x01, 0x40, 0xff, 0x08,
+ 0x03, 0x80, 0x40, 0x8f, 0x19, 0x0b, 0x80, 0x9f,
+ 0x89, 0xa7, 0x29, 0x1f, 0x80, 0x88, 0x29, 0x82,
+ 0xad, 0x8c, 0x01, 0x41, 0x95, 0x30, 0x28, 0x80,
+ 0xd1, 0x95, 0x0e, 0x01, 0x01, 0xf9, 0x2a, 0x00,
+ 0x08, 0x30, 0x80, 0xc7, 0x0a, 0x00, 0x80, 0x41,
+ 0x5a, 0x81, 0x8a, 0x81, 0xb3, 0x24, 0x00, 0x80,
+ 0x54, 0xec, 0x90, 0x85, 0x8e, 0x60, 0x36, 0x99,
+ 0x84, 0xba, 0x86, 0x88, 0x83, 0x44, 0x0a, 0x80,
+ 0xbe, 0x90, 0xbf, 0x08, 0x81, 0x60, 0x40, 0x0a,
+ 0x18, 0x30, 0x81, 0x4c, 0x9d, 0x08, 0x83, 0x52,
+ 0x5b, 0xad, 0x81, 0x96, 0x42, 0x1f, 0x82, 0x88,
+ 0x8f, 0x0e, 0x9d, 0x83, 0x40, 0x93, 0x82, 0x47,
+ 0xba, 0xb6, 0x83, 0xb1, 0x38, 0x8d, 0x80, 0x95,
+ 0x20, 0x8e, 0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01,
+ 0x04, 0x84, 0xbd, 0xa0, 0x80, 0x40, 0x9f, 0x8d,
+ 0x41, 0x6f, 0x80, 0xbc, 0x83, 0x41, 0xfa, 0x84,
+ 0x43, 0xdf, 0x86, 0xec, 0x87, 0x4a, 0xae, 0x84,
+ 0x6c, 0x0c, 0x00, 0x80, 0x9d, 0xdf, 0xff, 0x40,
+ 0xef,
};
static const uint8_t unicode_prop_Case_Ignorable_index[69] = {
- 0xbe, 0x05, 0x00, 0xfe, 0x07, 0x00, 0x52, 0x0a,
- 0xa0, 0xc1, 0x0b, 0x00, 0x82, 0x0d, 0x00, 0x3f,
- 0x10, 0x80, 0xd4, 0x17, 0x40, 0xcf, 0x1a, 0x20,
- 0xf5, 0x1c, 0x00, 0x80, 0x20, 0x00, 0x16, 0xa0,
- 0x00, 0xc6, 0xa8, 0x00, 0xc2, 0xaa, 0x60, 0x56,
- 0xfe, 0x20, 0xb1, 0x07, 0x01, 0x82, 0x10, 0x21,
- 0x02, 0x13, 0x21, 0xb8, 0x16, 0x61, 0x97, 0x1a,
- 0x01, 0x37, 0x6b, 0x21, 0x8c, 0xd1, 0x01, 0xd7,
- 0xe8, 0x41, 0xf0, 0x01, 0x0e,
+ 0xbe, 0x05, 0x00, // 005BE at 32
+ 0xfe, 0x07, 0x00, // 007FE at 64
+ 0x52, 0x0a, 0xa0, // 00A52 at 101
+ 0xc1, 0x0b, 0x00, // 00BC1 at 128
+ 0x82, 0x0d, 0x00, // 00D82 at 160
+ 0x3f, 0x10, 0x80, // 0103F at 196
+ 0xd4, 0x17, 0x40, // 017D4 at 226
+ 0xcf, 0x1a, 0x20, // 01ACF at 257
+ 0xf5, 0x1c, 0x00, // 01CF5 at 288
+ 0x80, 0x20, 0x00, // 02080 at 320
+ 0x16, 0xa0, 0x00, // 0A016 at 352
+ 0xc6, 0xa8, 0x00, // 0A8C6 at 384
+ 0xc2, 0xaa, 0x60, // 0AAC2 at 419
+ 0x56, 0xfe, 0x20, // 0FE56 at 449
+ 0xb1, 0x07, 0x01, // 107B1 at 480
+ 0x75, 0x10, 0x01, // 11075 at 512
+ 0xeb, 0x12, 0x21, // 112EB at 545
+ 0x41, 0x16, 0x01, // 11641 at 576
+ 0x5c, 0x1a, 0x01, // 11A5C at 608
+ 0x43, 0x1f, 0x01, // 11F43 at 640
+ 0x2e, 0xcf, 0x41, // 1CF2E at 674
+ 0x25, 0xe0, 0x01, // 1E025 at 704
+ 0xf0, 0x01, 0x0e, // E01F0 at 736 (upper bound)
};
-static const uint8_t unicode_prop_ID_Start_table[1079] = {
+static const uint8_t unicode_prop_ID_Start_table[1100] = {
0xc0, 0x99, 0x85, 0x99, 0xae, 0x80, 0x89, 0x03,
0x04, 0x96, 0x80, 0x9e, 0x80, 0x41, 0xc9, 0x83,
0x8b, 0x8d, 0x26, 0x00, 0x80, 0x40, 0x80, 0x20,
@@ -392,67 +414,92 @@ static const uint8_t unicode_prop_ID_Start_table[1079] = {
0xad, 0x94, 0x9a, 0x96, 0x8b, 0xb4, 0xb8, 0x09,
0x80, 0x8c, 0xac, 0x9f, 0x98, 0x99, 0xa3, 0x9c,
0x01, 0x07, 0xa2, 0x10, 0x8b, 0xaf, 0x8d, 0x83,
- 0x94, 0x00, 0x80, 0xa2, 0x91, 0x80, 0x98, 0xd3,
- 0x30, 0x00, 0x18, 0x8e, 0x80, 0x89, 0x86, 0xae,
- 0xa5, 0x39, 0x09, 0x95, 0x06, 0x01, 0x04, 0x10,
- 0x91, 0x80, 0x8b, 0x84, 0x40, 0x9d, 0xb4, 0x91,
- 0x83, 0x93, 0x82, 0x9d, 0xaf, 0x93, 0x08, 0x80,
- 0x40, 0xb7, 0xae, 0xa8, 0x83, 0xa3, 0xaf, 0x93,
- 0x80, 0xba, 0xaa, 0x8c, 0x80, 0xc6, 0x9a, 0xa4,
- 0x86, 0x40, 0xb8, 0xab, 0xf3, 0xbf, 0x9e, 0x39,
- 0x01, 0x38, 0x08, 0x97, 0x8e, 0x00, 0x80, 0xdd,
- 0x39, 0xa6, 0x8f, 0x00, 0x80, 0x9b, 0x80, 0x89,
- 0xa7, 0x30, 0x94, 0x80, 0x8a, 0xad, 0x92, 0x80,
- 0x91, 0xc8, 0x41, 0x06, 0x88, 0x80, 0xa4, 0x90,
- 0x80, 0xb0, 0x9d, 0xef, 0x30, 0x08, 0xa5, 0x94,
- 0x80, 0x98, 0x28, 0x08, 0x9f, 0x8d, 0x80, 0x41,
- 0x46, 0x92, 0x40, 0xbc, 0x80, 0xce, 0x43, 0x99,
- 0xe5, 0xee, 0x90, 0x40, 0xc3, 0x4a, 0x4b, 0xe0,
- 0x8e, 0x44, 0x2e, 0x4f, 0xd0, 0x42, 0x46, 0x60,
+ 0x94, 0x00, 0x80, 0xa2, 0x91, 0x80, 0x98, 0x92,
+ 0x81, 0xbe, 0x30, 0x00, 0x18, 0x8e, 0x80, 0x89,
+ 0x86, 0xae, 0xa5, 0x39, 0x09, 0x95, 0x06, 0x01,
+ 0x04, 0x10, 0x91, 0x80, 0x8b, 0x84, 0x40, 0x9d,
+ 0xb4, 0x91, 0x83, 0x93, 0x82, 0x9d, 0xaf, 0x93,
+ 0x08, 0x80, 0x40, 0xb7, 0xae, 0xa8, 0x83, 0xa3,
+ 0xaf, 0x93, 0x80, 0xba, 0xaa, 0x8c, 0x80, 0xc6,
+ 0x9a, 0xa4, 0x86, 0x40, 0xb8, 0xab, 0xf3, 0xbf,
+ 0x9e, 0x39, 0x01, 0x38, 0x08, 0x97, 0x8e, 0x00,
+ 0x80, 0xdd, 0x39, 0xa6, 0x8f, 0x00, 0x80, 0x9b,
+ 0x80, 0x89, 0xa7, 0x30, 0x94, 0x80, 0x8a, 0xad,
+ 0x92, 0x80, 0x91, 0xc8, 0x41, 0x06, 0x88, 0x80,
+ 0xa4, 0x90, 0x80, 0xb0, 0x9d, 0xef, 0x30, 0x08,
+ 0xa5, 0x94, 0x80, 0x98, 0x28, 0x08, 0x9f, 0x8d,
+ 0x80, 0x41, 0x46, 0x92, 0x8e, 0x00, 0x8c, 0x80,
+ 0xa1, 0xfb, 0x80, 0xce, 0x43, 0x99, 0xe5, 0xee,
+ 0x90, 0x40, 0xc3, 0x4a, 0x4b, 0xe0, 0x8e, 0x44,
+ 0x2f, 0x90, 0x85, 0x4f, 0xb8, 0x42, 0x46, 0x60,
0x21, 0xb8, 0x42, 0x38, 0x86, 0x9e, 0x90, 0xce,
0x90, 0x9d, 0x91, 0xaf, 0x8f, 0x83, 0x9e, 0x94,
0x84, 0x92, 0x42, 0xaf, 0xbf, 0xff, 0xca, 0x20,
0xc1, 0x8c, 0xbf, 0x08, 0x80, 0x9b, 0x57, 0xf7,
0x87, 0x44, 0xd5, 0xa9, 0x88, 0x60, 0x22, 0xe6,
- 0x18, 0x30, 0x08, 0x41, 0x22, 0xac, 0x82, 0x90,
- 0x1f, 0x41, 0x8b, 0x49, 0x03, 0xea, 0x84, 0x8c,
- 0x82, 0x88, 0x86, 0x89, 0x57, 0x65, 0xd4, 0x80,
- 0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80, 0x8b, 0x00,
- 0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06, 0x80, 0x9b,
- 0x03, 0x04, 0x00, 0x16, 0x80, 0x41, 0x53, 0x81,
- 0x98, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80,
- 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80,
- 0x9e, 0x80, 0x98, 0x07, 0x47, 0x33, 0x9e, 0x41,
- 0xe0, 0xac, 0x89, 0x86, 0x8f, 0x80, 0x41, 0x40,
- 0x9d, 0x91, 0xab, 0x44, 0xf3, 0x30, 0x18, 0x08,
- 0x8e, 0x80, 0x40, 0xc4, 0xba, 0xc3, 0x30, 0x44,
- 0xb3, 0x18, 0x9a, 0x01, 0x00, 0x08, 0x80, 0x89,
- 0x03, 0x00, 0x00, 0x28, 0x18, 0x00, 0x00, 0x02,
- 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00, 0x80, 0x89,
- 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, 0x51, 0x43,
- 0x60, 0xa6, 0xdf, 0x9f, 0x50, 0x38, 0x86, 0x40,
- 0xdd, 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x4c,
- 0x1e, 0x42, 0x1d, 0x45, 0xe1, 0x53, 0x4a,
+ 0x18, 0x30, 0x08, 0x41, 0x22, 0x8e, 0x80, 0x9c,
+ 0x11, 0x80, 0x8d, 0x1f, 0x41, 0x8b, 0x49, 0x03,
+ 0xea, 0x84, 0x8c, 0x82, 0x88, 0x86, 0x89, 0x57,
+ 0x65, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b,
+ 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f,
+ 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80,
+ 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80, 0x9e,
+ 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e,
+ 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, 0x47,
+ 0x33, 0x9e, 0x2d, 0x41, 0x04, 0xbd, 0x40, 0x91,
+ 0xac, 0x89, 0x86, 0x8f, 0x80, 0x41, 0x40, 0x9d,
+ 0x91, 0xab, 0x41, 0xe3, 0x9b, 0x42, 0xf3, 0x30,
+ 0x18, 0x08, 0x8e, 0x80, 0x40, 0xc4, 0xba, 0xc3,
+ 0x30, 0x44, 0xb3, 0x18, 0x9a, 0x01, 0x00, 0x08,
+ 0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18, 0x00,
+ 0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00,
+ 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90,
+ 0x51, 0x43, 0x60, 0xa6, 0xdf, 0x9f, 0x50, 0x39,
+ 0x85, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d, 0x5d,
+ 0x30, 0x4c, 0x1e, 0x42, 0x1d, 0x45, 0xe1, 0x53,
+ 0x4a, 0x84, 0x50, 0x5f,
};
-static const uint8_t unicode_prop_ID_Start_index[102] = {
- 0xf6, 0x03, 0x20, 0xa6, 0x07, 0x00, 0xa9, 0x09,
- 0x20, 0xb1, 0x0a, 0x00, 0xba, 0x0b, 0x20, 0x3b,
- 0x0d, 0x20, 0xc7, 0x0e, 0x20, 0x49, 0x12, 0x00,
- 0x9b, 0x16, 0x00, 0xac, 0x19, 0x00, 0xc0, 0x1d,
- 0x80, 0x80, 0x20, 0x20, 0x70, 0x2d, 0x00, 0x00,
- 0x32, 0x00, 0xda, 0xa7, 0x00, 0x4c, 0xaa, 0x20,
- 0xc7, 0xd7, 0x20, 0xfc, 0xfd, 0x20, 0x9d, 0x02,
- 0x21, 0x96, 0x05, 0x01, 0xf3, 0x08, 0x01, 0xb3,
- 0x0c, 0x21, 0x73, 0x11, 0x61, 0x3e, 0x13, 0x01,
- 0x47, 0x17, 0x21, 0x9e, 0x1a, 0x01, 0x9a, 0x23,
- 0x01, 0x78, 0x6b, 0x01, 0xfc, 0xb2, 0x61, 0x3a,
- 0xd5, 0x01, 0x2d, 0xe1, 0x41, 0x33, 0xee, 0x01,
- 0xe0, 0xa6, 0x62, 0x4b, 0x13, 0x03,
+static const uint8_t unicode_prop_ID_Start_index[105] = {
+ 0xf6, 0x03, 0x20, // 003F6 at 33
+ 0xa6, 0x07, 0x00, // 007A6 at 64
+ 0xa9, 0x09, 0x20, // 009A9 at 97
+ 0xb1, 0x0a, 0x00, // 00AB1 at 128
+ 0xba, 0x0b, 0x20, // 00BBA at 161
+ 0x3b, 0x0d, 0x20, // 00D3B at 193
+ 0xc7, 0x0e, 0x20, // 00EC7 at 225
+ 0x49, 0x12, 0x00, // 01249 at 256
+ 0x9b, 0x16, 0x00, // 0169B at 288
+ 0xac, 0x19, 0x00, // 019AC at 320
+ 0xc0, 0x1d, 0x80, // 01DC0 at 356
+ 0x80, 0x20, 0x20, // 02080 at 385
+ 0x70, 0x2d, 0x00, // 02D70 at 416
+ 0x00, 0x32, 0x00, // 03200 at 448
+ 0xda, 0xa7, 0x00, // 0A7DA at 480
+ 0x4c, 0xaa, 0x20, // 0AA4C at 513
+ 0xc7, 0xd7, 0x20, // 0D7C7 at 545
+ 0xfc, 0xfd, 0x20, // 0FDFC at 577
+ 0x9d, 0x02, 0x21, // 1029D at 609
+ 0x96, 0x05, 0x01, // 10596 at 640
+ 0xf3, 0x08, 0x01, // 108F3 at 672
+ 0xb3, 0x0c, 0x21, // 10CB3 at 705
+ 0x73, 0x11, 0x61, // 11173 at 739
+ 0x34, 0x13, 0x01, // 11334 at 768
+ 0x1b, 0x17, 0x21, // 1171B at 801
+ 0x8a, 0x1a, 0x01, // 11A8A at 832
+ 0x34, 0x1f, 0x21, // 11F34 at 865
+ 0xbf, 0x6a, 0x01, // 16ABF at 896
+ 0x23, 0xb1, 0xa1, // 1B123 at 933
+ 0xad, 0xd4, 0x01, // 1D4AD at 960
+ 0x6f, 0xd7, 0x01, // 1D76F at 992
+ 0xff, 0xe7, 0x61, // 1E7FF at 1027
+ 0x5e, 0xee, 0x01, // 1EE5E at 1056
+ 0xe1, 0xeb, 0x22, // 2EBE1 at 1089
+ 0xb0, 0x23, 0x03, // 323B0 at 1120 (upper bound)
};
-static const uint8_t unicode_prop_ID_Continue1_table[640] = {
+static const uint8_t unicode_prop_ID_Continue1_table[660] = {
0xaf, 0x89, 0xa4, 0x80, 0xd6, 0x80, 0x42, 0x47,
0xef, 0x96, 0x80, 0x40, 0xfa, 0x84, 0x41, 0x08,
0xac, 0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf,
@@ -470,85 +517,101 @@ static const uint8_t unicode_prop_ID_Continue1_table[640] = {
0xba, 0x22, 0x10, 0x83, 0x88, 0x80, 0x8d, 0x89,
0x8f, 0x84, 0xb6, 0x00, 0x30, 0x10, 0x1e, 0x81,
0x8a, 0x09, 0x89, 0x90, 0x82, 0xb7, 0x00, 0x30,
- 0x10, 0x1e, 0x81, 0x8a, 0x09, 0x89, 0x8f, 0x83,
- 0xb6, 0x08, 0x30, 0x10, 0x83, 0x88, 0x80, 0x89,
- 0x09, 0x89, 0x90, 0x82, 0xc5, 0x03, 0x28, 0x00,
- 0x3d, 0x89, 0x09, 0xbc, 0x01, 0x86, 0x8b, 0x38,
- 0x89, 0xd6, 0x01, 0x88, 0x8a, 0x29, 0x89, 0xbd,
- 0x0d, 0x89, 0x8a, 0x00, 0x00, 0x03, 0x81, 0xb0,
- 0x93, 0x01, 0x84, 0x8a, 0x80, 0xa3, 0x88, 0x80,
- 0xe3, 0x93, 0x80, 0x89, 0x8b, 0x1b, 0x10, 0x11,
- 0x32, 0x83, 0x8c, 0x8b, 0x80, 0x8e, 0x42, 0xbe,
- 0x82, 0x88, 0x88, 0x43, 0x9f, 0x83, 0x9b, 0x82,
- 0x9c, 0x81, 0x9d, 0x81, 0xbf, 0x9f, 0x88, 0x01,
- 0x89, 0xa0, 0x10, 0x8a, 0x40, 0x8e, 0x80, 0xf5,
- 0x8b, 0x83, 0x8b, 0x89, 0x89, 0xff, 0x8a, 0xbb,
- 0x84, 0xb8, 0x89, 0x80, 0x9c, 0x81, 0x8a, 0x85,
- 0x89, 0x95, 0x8d, 0x80, 0x8f, 0xb0, 0x84, 0xae,
- 0x90, 0x8a, 0x89, 0x90, 0x88, 0x8b, 0x82, 0x9d,
- 0x8c, 0x81, 0x89, 0xab, 0x8d, 0xaf, 0x93, 0x87,
- 0x89, 0x85, 0x89, 0xf5, 0x10, 0x94, 0x18, 0x28,
- 0x0a, 0x40, 0xc5, 0xbf, 0x42, 0x3e, 0x81, 0x92,
- 0x80, 0xfa, 0x8c, 0x18, 0x82, 0x8b, 0x4b, 0xfd,
- 0x82, 0x40, 0x8c, 0x80, 0xdf, 0x9f, 0x42, 0x29,
- 0x85, 0xe8, 0x81, 0x60, 0x75, 0x84, 0x89, 0xc4,
- 0x03, 0x89, 0x9f, 0x81, 0xcf, 0x81, 0x41, 0x0f,
- 0x02, 0x03, 0x80, 0x96, 0x23, 0x80, 0xd2, 0x81,
- 0xb1, 0x91, 0x89, 0x89, 0x85, 0x91, 0x8c, 0x8a,
- 0x9b, 0x87, 0x98, 0x8c, 0xab, 0x83, 0xae, 0x8d,
- 0x8e, 0x89, 0x8a, 0x80, 0x89, 0x89, 0xae, 0x8d,
- 0x8b, 0x07, 0x09, 0x89, 0xa0, 0x82, 0xb1, 0x00,
- 0x11, 0x0c, 0x08, 0x80, 0xa8, 0x24, 0x81, 0x40,
- 0xeb, 0x38, 0x09, 0x89, 0x60, 0x4f, 0x23, 0x80,
- 0x42, 0xe0, 0x8f, 0x8f, 0x8f, 0x11, 0x97, 0x82,
- 0x40, 0xbf, 0x89, 0xa4, 0x80, 0x42, 0xbc, 0x80,
- 0x40, 0xe1, 0x80, 0x40, 0x94, 0x84, 0x41, 0x24,
- 0x89, 0x45, 0x56, 0x10, 0x0c, 0x83, 0xa7, 0x13,
- 0x80, 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x1f, 0x89,
- 0x41, 0x70, 0x81, 0x40, 0x98, 0x8a, 0xb0, 0x83,
- 0xf9, 0x82, 0xb4, 0x8e, 0x9e, 0x8a, 0x09, 0x89,
- 0x83, 0xac, 0x8a, 0x30, 0xac, 0x89, 0x2a, 0xa3,
- 0x8d, 0x80, 0x89, 0x21, 0xab, 0x80, 0x8b, 0x82,
- 0xaf, 0x8d, 0x3b, 0x80, 0x8b, 0xd1, 0x8b, 0x28,
- 0x40, 0x9f, 0x8b, 0x84, 0x89, 0x2b, 0xb6, 0x08,
- 0x31, 0x09, 0x82, 0x88, 0x80, 0x89, 0x09, 0x32,
- 0x84, 0x40, 0xbf, 0x91, 0x88, 0x89, 0x18, 0xd0,
- 0x93, 0x8b, 0x89, 0x40, 0xd4, 0x31, 0x88, 0x9a,
- 0x81, 0xd1, 0x90, 0x8e, 0x89, 0xd0, 0x8c, 0x87,
- 0x89, 0xd2, 0x8e, 0x83, 0x89, 0x40, 0xf1, 0x8e,
- 0x40, 0xa4, 0x89, 0xc5, 0x28, 0x09, 0x18, 0x00,
- 0x81, 0x8b, 0x89, 0xf6, 0x31, 0x32, 0x80, 0x9b,
- 0x89, 0xa7, 0x30, 0x1f, 0x80, 0x88, 0x8a, 0xad,
- 0x8f, 0x41, 0x94, 0x38, 0x87, 0x8f, 0x89, 0xb7,
- 0x95, 0x80, 0x8d, 0xf9, 0x2a, 0x00, 0x08, 0x30,
- 0x07, 0x89, 0xaf, 0x20, 0x08, 0x27, 0x89, 0x41,
- 0x48, 0x83, 0x60, 0x4b, 0x68, 0x89, 0xd5, 0x89,
- 0xa5, 0x84, 0xba, 0x86, 0x98, 0x89, 0x43, 0xf4,
- 0x00, 0xb6, 0x33, 0xd0, 0x80, 0x8a, 0x81, 0x60,
- 0x4c, 0xaa, 0x81, 0x52, 0x60, 0xad, 0x81, 0x96,
- 0x42, 0x1d, 0x22, 0x2f, 0x39, 0x86, 0x9d, 0x83,
- 0x40, 0x93, 0x82, 0x45, 0x88, 0xb1, 0x41, 0xff,
- 0xb6, 0x83, 0xb1, 0x38, 0x8d, 0x80, 0x95, 0x20,
- 0x8e, 0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04,
- 0x41, 0x04, 0x86, 0x88, 0x89, 0x41, 0x63, 0x80,
- 0xbc, 0x8d, 0x45, 0xd5, 0x86, 0xec, 0x34, 0x89,
- 0x52, 0x95, 0x89, 0x6c, 0x05, 0x05, 0x40, 0xef,
+ 0x10, 0x1e, 0x81, 0x8a, 0x09, 0x89, 0x10, 0x8b,
+ 0x83, 0xb6, 0x08, 0x30, 0x10, 0x83, 0x88, 0x80,
+ 0x89, 0x09, 0x89, 0x90, 0x82, 0xc5, 0x03, 0x28,
+ 0x00, 0x3d, 0x89, 0x09, 0xbc, 0x01, 0x86, 0x8b,
+ 0x38, 0x89, 0xd6, 0x01, 0x88, 0x8a, 0x30, 0x89,
+ 0xbd, 0x0d, 0x89, 0x8a, 0x00, 0x00, 0x03, 0x81,
+ 0xb0, 0x93, 0x01, 0x84, 0x8a, 0x80, 0xa3, 0x88,
+ 0x80, 0xe3, 0x93, 0x80, 0x89, 0x8b, 0x1b, 0x10,
+ 0x11, 0x32, 0x83, 0x8c, 0x8b, 0x80, 0x8e, 0x42,
+ 0xbe, 0x82, 0x88, 0x88, 0x43, 0x9f, 0x83, 0x9b,
+ 0x82, 0x9c, 0x81, 0x9d, 0x81, 0xbf, 0x9f, 0x88,
+ 0x01, 0x89, 0xa0, 0x10, 0x8a, 0x40, 0x8e, 0x80,
+ 0xf5, 0x8b, 0x83, 0x8b, 0x89, 0x89, 0xff, 0x8a,
+ 0xbb, 0x84, 0xb8, 0x89, 0x80, 0x9c, 0x81, 0x8a,
+ 0x85, 0x89, 0x95, 0x8d, 0x80, 0x8f, 0xb0, 0x84,
+ 0xae, 0x90, 0x8a, 0x89, 0x90, 0x88, 0x8b, 0x82,
+ 0x9d, 0x8c, 0x81, 0x89, 0xab, 0x8d, 0xaf, 0x93,
+ 0x87, 0x89, 0x85, 0x89, 0xf5, 0x10, 0x94, 0x18,
+ 0x28, 0x0a, 0x40, 0xc5, 0xbf, 0x42, 0x3e, 0x81,
+ 0x92, 0x80, 0xfa, 0x8c, 0x18, 0x82, 0x8b, 0x4b,
+ 0xfd, 0x82, 0x40, 0x8c, 0x80, 0xdf, 0x9f, 0x42,
+ 0x29, 0x85, 0xe8, 0x81, 0x60, 0x75, 0x84, 0x89,
+ 0xc4, 0x03, 0x89, 0x9f, 0x81, 0xcf, 0x81, 0x41,
+ 0x0f, 0x02, 0x03, 0x80, 0x96, 0x23, 0x80, 0xd2,
+ 0x81, 0xb1, 0x91, 0x89, 0x89, 0x85, 0x91, 0x8c,
+ 0x8a, 0x9b, 0x87, 0x98, 0x8c, 0xab, 0x83, 0xae,
+ 0x8d, 0x8e, 0x89, 0x8a, 0x80, 0x89, 0x89, 0xae,
+ 0x8d, 0x8b, 0x07, 0x09, 0x89, 0xa0, 0x82, 0xb1,
+ 0x00, 0x11, 0x0c, 0x08, 0x80, 0xa8, 0x24, 0x81,
+ 0x40, 0xeb, 0x38, 0x09, 0x89, 0x60, 0x4f, 0x23,
+ 0x80, 0x42, 0xe0, 0x8f, 0x8f, 0x8f, 0x11, 0x97,
+ 0x82, 0x40, 0xbf, 0x89, 0xa4, 0x80, 0x42, 0xbc,
+ 0x80, 0x40, 0xe1, 0x80, 0x40, 0x94, 0x84, 0x41,
+ 0x24, 0x89, 0x45, 0x56, 0x10, 0x0c, 0x83, 0xa7,
+ 0x13, 0x80, 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x1f,
+ 0x89, 0x41, 0x70, 0x81, 0xcf, 0x82, 0xc5, 0x8a,
+ 0xb0, 0x83, 0xf9, 0x82, 0xb4, 0x8e, 0x9e, 0x8a,
+ 0x09, 0x89, 0x83, 0xac, 0x8a, 0x30, 0xac, 0x89,
+ 0x2a, 0xa3, 0x8d, 0x80, 0x89, 0x21, 0xab, 0x80,
+ 0x8b, 0x82, 0xaf, 0x8d, 0x3b, 0x80, 0x8b, 0xd1,
+ 0x8b, 0x28, 0x08, 0x40, 0x9c, 0x8b, 0x84, 0x89,
+ 0x2b, 0xb6, 0x08, 0x31, 0x09, 0x82, 0x88, 0x80,
+ 0x89, 0x09, 0x32, 0x84, 0x40, 0xbf, 0x91, 0x88,
+ 0x89, 0x18, 0xd0, 0x93, 0x8b, 0x89, 0x40, 0xd4,
+ 0x31, 0x88, 0x9a, 0x81, 0xd1, 0x90, 0x8e, 0x89,
+ 0xd0, 0x8c, 0x87, 0x89, 0xd2, 0x8e, 0x83, 0x89,
+ 0x40, 0xf1, 0x8e, 0x40, 0xa4, 0x89, 0xc5, 0x28,
+ 0x09, 0x18, 0x00, 0x81, 0x8b, 0x89, 0xf6, 0x31,
+ 0x32, 0x80, 0x9b, 0x89, 0xa7, 0x30, 0x1f, 0x80,
+ 0x88, 0x8a, 0xad, 0x8f, 0x41, 0x94, 0x38, 0x87,
+ 0x8f, 0x89, 0xb7, 0x95, 0x80, 0x8d, 0xf9, 0x2a,
+ 0x00, 0x08, 0x30, 0x07, 0x89, 0xaf, 0x20, 0x08,
+ 0x27, 0x89, 0x41, 0x48, 0x83, 0x88, 0x08, 0x80,
+ 0xaf, 0x32, 0x84, 0x8c, 0x89, 0x54, 0xe5, 0x05,
+ 0x8e, 0x60, 0x36, 0x09, 0x89, 0xd5, 0x89, 0xa5,
+ 0x84, 0xba, 0x86, 0x98, 0x89, 0x43, 0xf4, 0x00,
+ 0xb6, 0x33, 0xd0, 0x80, 0x8a, 0x81, 0x60, 0x4c,
+ 0xaa, 0x81, 0x52, 0x60, 0xad, 0x81, 0x96, 0x42,
+ 0x1d, 0x22, 0x2f, 0x39, 0x86, 0x9d, 0x83, 0x40,
+ 0x93, 0x82, 0x45, 0x88, 0xb1, 0x41, 0xff, 0xb6,
+ 0x83, 0xb1, 0x38, 0x8d, 0x80, 0x95, 0x20, 0x8e,
+ 0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04, 0xe3,
+ 0x80, 0x40, 0x9f, 0x86, 0x88, 0x89, 0x41, 0x63,
+ 0x80, 0xbc, 0x8d, 0x41, 0xf1, 0x8d, 0x43, 0xd5,
+ 0x86, 0xec, 0x34, 0x89, 0x52, 0x95, 0x89, 0x6c,
+ 0x05, 0x05, 0x40, 0xef,
};
-static const uint8_t unicode_prop_ID_Continue1_index[60] = {
- 0xfa, 0x06, 0x00, 0x70, 0x09, 0x00, 0xf0, 0x0a,
- 0x40, 0x57, 0x0c, 0x00, 0xf0, 0x0d, 0x40, 0xc7,
- 0x0f, 0x00, 0xea, 0x17, 0x20, 0x45, 0x1b, 0x20,
- 0x55, 0x20, 0x20, 0x0c, 0xa8, 0x60, 0x37, 0xaa,
- 0x00, 0x50, 0xfe, 0x00, 0x3a, 0x0d, 0x01, 0x83,
- 0x11, 0x01, 0xc4, 0x14, 0x21, 0x44, 0x19, 0x21,
- 0x5a, 0x1d, 0x41, 0x9f, 0xbc, 0x61, 0xb0, 0xda,
- 0x21, 0xf0, 0x01, 0x0e,
+static const uint8_t unicode_prop_ID_Continue1_index[63] = {
+ 0xfa, 0x06, 0x00, // 006FA at 32
+ 0x70, 0x09, 0x00, // 00970 at 64
+ 0xf0, 0x0a, 0x40, // 00AF0 at 98
+ 0x57, 0x0c, 0x00, // 00C57 at 128
+ 0xf0, 0x0d, 0x60, // 00DF0 at 163
+ 0xc7, 0x0f, 0x20, // 00FC7 at 193
+ 0xea, 0x17, 0x40, // 017EA at 226
+ 0x05, 0x1b, 0x00, // 01B05 at 256
+ 0x41, 0x20, 0x00, // 02041 at 288
+ 0x0c, 0xa8, 0x80, // 0A80C at 324
+ 0x37, 0xaa, 0x20, // 0AA37 at 353
+ 0x50, 0xfe, 0x20, // 0FE50 at 385
+ 0x3a, 0x0d, 0x21, // 10D3A at 417
+ 0x74, 0x11, 0x01, // 11174 at 448
+ 0x5a, 0x14, 0x21, // 1145A at 481
+ 0x44, 0x19, 0x81, // 11944 at 516
+ 0x5a, 0x1d, 0xa1, // 11D5A at 549
+ 0xf5, 0x6a, 0x21, // 16AF5 at 577
+ 0x45, 0xd2, 0x41, // 1D245 at 610
+ 0xaf, 0xe2, 0x21, // 1E2AF at 641
+ 0xf0, 0x01, 0x0e, // E01F0 at 672 (upper bound)
};
#ifdef CONFIG_ALL_UNICODE
-static const uint8_t unicode_cc_table[881] = {
+static const uint8_t unicode_cc_table[899] = {
0xb2, 0xcf, 0xd4, 0x00, 0xe8, 0x03, 0xdc, 0x00,
0xe8, 0x00, 0xd8, 0x04, 0xdc, 0x01, 0xca, 0x03,
0xdc, 0x01, 0xca, 0x0a, 0xdc, 0x04, 0x01, 0x03,
@@ -631,52 +694,72 @@ static const uint8_t unicode_cc_table[881] = {
0xb6, 0x61, 0x00, 0xdc, 0x80, 0xc0, 0xa7, 0xc0,
0x00, 0x01, 0x00, 0xdc, 0x83, 0x00, 0x09, 0xb0,
0x74, 0xc0, 0x00, 0xdc, 0xb2, 0x0c, 0xc3, 0xb1,
- 0x52, 0xc1, 0xb0, 0x68, 0x01, 0xdc, 0xc2, 0x00,
- 0xdc, 0xc0, 0x03, 0xdc, 0xb0, 0x00, 0xc0, 0x00,
- 0xdc, 0xc0, 0x00, 0xdc, 0xb0, 0x8f, 0x00, 0x09,
- 0xa8, 0x00, 0x09, 0x8d, 0x00, 0x09, 0xb0, 0x08,
- 0x00, 0x09, 0x00, 0x07, 0xb0, 0x14, 0xc2, 0xaf,
- 0x01, 0x09, 0xb0, 0x0d, 0x00, 0x07, 0xb0, 0x1b,
- 0x00, 0x09, 0x88, 0x00, 0x07, 0xb0, 0x39, 0x00,
- 0x09, 0x00, 0x07, 0xb0, 0x81, 0x00, 0x07, 0x00,
- 0x09, 0xb0, 0x1f, 0x01, 0x07, 0x8f, 0x00, 0x09,
- 0x97, 0xc6, 0x82, 0xc4, 0xb0, 0x9c, 0x00, 0x09,
- 0x82, 0x00, 0x07, 0x96, 0xc0, 0xb0, 0x32, 0x00,
- 0x09, 0x00, 0x07, 0xb0, 0xca, 0x00, 0x09, 0x00,
- 0x07, 0xb0, 0x4d, 0x00, 0x09, 0xb0, 0x45, 0x00,
- 0x09, 0x00, 0x07, 0xb0, 0x42, 0x00, 0x09, 0xb0,
- 0xdc, 0x00, 0x09, 0x00, 0x07, 0xb0, 0xd1, 0x01,
- 0x09, 0x83, 0x00, 0x07, 0xb0, 0x6b, 0x00, 0x09,
- 0xb0, 0x22, 0x00, 0x09, 0x91, 0x00, 0x09, 0xb0,
- 0x20, 0x00, 0x09, 0xb1, 0x74, 0x00, 0x09, 0xb0,
- 0xd1, 0x00, 0x07, 0x80, 0x01, 0x09, 0xb0, 0x20,
- 0x00, 0x09, 0xb8, 0x45, 0x27, 0x04, 0x01, 0xb0,
+ 0x52, 0xc1, 0xb0, 0x1f, 0x02, 0xdc, 0xb0, 0x15,
+ 0x01, 0xdc, 0xc2, 0x00, 0xdc, 0xc0, 0x03, 0xdc,
+ 0xb0, 0x00, 0xc0, 0x00, 0xdc, 0xc0, 0x00, 0xdc,
+ 0xb0, 0x8f, 0x00, 0x09, 0xa8, 0x00, 0x09, 0x8d,
+ 0x00, 0x09, 0xb0, 0x08, 0x00, 0x09, 0x00, 0x07,
+ 0xb0, 0x14, 0xc2, 0xaf, 0x01, 0x09, 0xb0, 0x0d,
+ 0x00, 0x07, 0xb0, 0x1b, 0x00, 0x09, 0x88, 0x00,
+ 0x07, 0xb0, 0x39, 0x00, 0x09, 0x00, 0x07, 0xb0,
+ 0x81, 0x00, 0x07, 0x00, 0x09, 0xb0, 0x1f, 0x01,
+ 0x07, 0x8f, 0x00, 0x09, 0x97, 0xc6, 0x82, 0xc4,
+ 0xb0, 0x9c, 0x00, 0x09, 0x82, 0x00, 0x07, 0x96,
+ 0xc0, 0xb0, 0x32, 0x00, 0x09, 0x00, 0x07, 0xb0,
+ 0xca, 0x00, 0x09, 0x00, 0x07, 0xb0, 0x4d, 0x00,
+ 0x09, 0xb0, 0x45, 0x00, 0x09, 0x00, 0x07, 0xb0,
+ 0x42, 0x00, 0x09, 0xb0, 0xdc, 0x00, 0x09, 0x00,
+ 0x07, 0xb0, 0xd1, 0x01, 0x09, 0x83, 0x00, 0x07,
+ 0xb0, 0x6b, 0x00, 0x09, 0xb0, 0x22, 0x00, 0x09,
+ 0x91, 0x00, 0x09, 0xb0, 0x20, 0x00, 0x09, 0xb1,
+ 0x74, 0x00, 0x09, 0xb0, 0xd1, 0x00, 0x07, 0x80,
+ 0x01, 0x09, 0xb0, 0x20, 0x00, 0x09, 0xb1, 0x78,
+ 0x01, 0x09, 0xb8, 0x43, 0x7c, 0x04, 0x01, 0xb0,
0x0a, 0xc6, 0xb4, 0x88, 0x01, 0x06, 0xb8, 0x44,
0x7b, 0x00, 0x01, 0xb8, 0x0c, 0x95, 0x01, 0xd8,
0x02, 0x01, 0x82, 0x00, 0xe2, 0x04, 0xd8, 0x87,
0x07, 0xdc, 0x81, 0xc4, 0x01, 0xdc, 0x9d, 0xc3,
0xb0, 0x63, 0xc2, 0xb8, 0x05, 0x8a, 0xc6, 0x80,
0xd0, 0x81, 0xc6, 0x80, 0xc1, 0x80, 0xc4, 0xb0,
- 0xd4, 0xc6, 0xb1, 0x46, 0xc0, 0xb0, 0x0c, 0xc3,
- 0xb5, 0xaf, 0x06, 0xdc, 0xb0, 0x3c, 0xc5, 0x00,
- 0x07,
+ 0x33, 0xc0, 0xb0, 0x6f, 0xc6, 0xb1, 0x46, 0xc0,
+ 0xb0, 0x0c, 0xc3, 0xb1, 0xcb, 0x01, 0xe8, 0x00,
+ 0xdc, 0xc0, 0xb3, 0xaf, 0x06, 0xdc, 0xb0, 0x3c,
+ 0xc5, 0x00, 0x07,
};
-static const uint8_t unicode_cc_index[84] = {
- 0x4d, 0x03, 0x00, 0x97, 0x05, 0x20, 0xc6, 0x05,
- 0x00, 0xe7, 0x06, 0x00, 0x45, 0x07, 0x00, 0x9c,
- 0x08, 0x00, 0x4d, 0x09, 0x00, 0x3c, 0x0b, 0x00,
- 0x3d, 0x0d, 0x00, 0x36, 0x0f, 0x00, 0x38, 0x10,
- 0x20, 0x3a, 0x19, 0x00, 0xcb, 0x1a, 0x20, 0xd3,
- 0x1c, 0x00, 0xcf, 0x1d, 0x00, 0xe2, 0x20, 0x00,
- 0x2e, 0x30, 0x20, 0x2b, 0xa9, 0x20, 0xed, 0xab,
- 0x00, 0x39, 0x0a, 0x01, 0x84, 0x0f, 0x21, 0xc0,
- 0x11, 0x01, 0x43, 0x14, 0x01, 0x39, 0x18, 0x21,
- 0x42, 0x1d, 0x21, 0x67, 0xd1, 0x01, 0x30, 0xe1,
- 0x21, 0x4b, 0xe9, 0x01,
+static const uint8_t unicode_cc_index[87] = {
+ 0x4d, 0x03, 0x00, // 0034D at 32
+ 0x97, 0x05, 0x20, // 00597 at 65
+ 0xc6, 0x05, 0x00, // 005C6 at 96
+ 0xe7, 0x06, 0x00, // 006E7 at 128
+ 0x45, 0x07, 0x00, // 00745 at 160
+ 0x9c, 0x08, 0x00, // 0089C at 192
+ 0x4d, 0x09, 0x00, // 0094D at 224
+ 0x3c, 0x0b, 0x00, // 00B3C at 256
+ 0x3d, 0x0d, 0x00, // 00D3D at 288
+ 0x36, 0x0f, 0x00, // 00F36 at 320
+ 0x38, 0x10, 0x20, // 01038 at 353
+ 0x3a, 0x19, 0x00, // 0193A at 384
+ 0xcb, 0x1a, 0x20, // 01ACB at 417
+ 0xd3, 0x1c, 0x00, // 01CD3 at 448
+ 0xcf, 0x1d, 0x00, // 01DCF at 480
+ 0xe2, 0x20, 0x00, // 020E2 at 512
+ 0x2e, 0x30, 0x20, // 0302E at 545
+ 0x2b, 0xa9, 0x20, // 0A92B at 577
+ 0xed, 0xab, 0x00, // 0ABED at 608
+ 0x39, 0x0a, 0x01, // 10A39 at 640
+ 0x51, 0x0f, 0x01, // 10F51 at 672
+ 0x73, 0x11, 0x01, // 11173 at 704
+ 0x75, 0x13, 0x01, // 11375 at 736
+ 0x2b, 0x17, 0x21, // 1172B at 769
+ 0x3f, 0x1c, 0x21, // 11C3F at 801
+ 0x9e, 0xbc, 0x21, // 1BC9E at 833
+ 0x08, 0xe0, 0x01, // 1E008 at 864
+ 0x44, 0xe9, 0x01, // 1E944 at 896
+ 0x4b, 0xe9, 0x01, // 1E94B at 928 (upper bound)
};
-static const uint32_t unicode_decomp_table1[693] = {
+static const uint32_t unicode_decomp_table1[699] = {
0x00280081, 0x002a0097, 0x002a8081, 0x002bc097,
0x002c8115, 0x002d0097, 0x002d4081, 0x002e0097,
0x002e4115, 0x002f0199, 0x00302016, 0x00400842,
@@ -840,20 +923,21 @@ static const uint32_t unicode_decomp_table1[693] = {
0x75e24081, 0x75e2832d, 0x75e4089f, 0x75e84081,
0x75e8839f, 0x75ea4081, 0x75ea8c9f, 0x75f0c081,
0x75f1042d, 0x75f3851f, 0x75f6051f, 0x75f8851f,
- 0x75fb051f, 0x75fd851f, 0x7b80022d, 0x7b814dad,
- 0x7b884203, 0x7b89c081, 0x7b8a452d, 0x7b8d0403,
- 0x7b908081, 0x7b91dc03, 0x7ba0052d, 0x7ba2c8ad,
- 0x7ba84483, 0x7baac8ad, 0x7c400097, 0x7c404521,
- 0x7c440d25, 0x7c4a8087, 0x7c4ac115, 0x7c4b4117,
- 0x7c4c0d1f, 0x7c528217, 0x7c538099, 0x7c53c097,
- 0x7c5a8197, 0x7c640097, 0x7c80012f, 0x7c808081,
- 0x7c841603, 0x7c9004c1, 0x7c940103, 0x7efc051f,
- 0xbe0001ac, 0xbe00d110, 0xbe0947ac, 0xbe0d3910,
- 0xbe29872c, 0xbe2d022c, 0xbe2e3790, 0xbe49ff90,
- 0xbe69bc10,
+ 0x75fb051f, 0x75fd851f, 0x780c049f, 0x780e419f,
+ 0x780f059f, 0x7811c203, 0x7812d0ad, 0x781b0103,
+ 0x7b80022d, 0x7b814dad, 0x7b884203, 0x7b89c081,
+ 0x7b8a452d, 0x7b8d0403, 0x7b908081, 0x7b91dc03,
+ 0x7ba0052d, 0x7ba2c8ad, 0x7ba84483, 0x7baac8ad,
+ 0x7c400097, 0x7c404521, 0x7c440d25, 0x7c4a8087,
+ 0x7c4ac115, 0x7c4b4117, 0x7c4c0d1f, 0x7c528217,
+ 0x7c538099, 0x7c53c097, 0x7c5a8197, 0x7c640097,
+ 0x7c80012f, 0x7c808081, 0x7c841603, 0x7c9004c1,
+ 0x7c940103, 0x7efc051f, 0xbe0001ac, 0xbe00d110,
+ 0xbe0947ac, 0xbe0d3910, 0xbe29872c, 0xbe2d022c,
+ 0xbe2e3790, 0xbe49ff90, 0xbe69bc10,
};
-static const uint16_t unicode_decomp_table2[693] = {
+static const uint16_t unicode_decomp_table2[699] = {
0x0020, 0x0000, 0x0061, 0x0002, 0x0004, 0x0006, 0x03bc, 0x0008,
0x000a, 0x000c, 0x0015, 0x0095, 0x00a5, 0x00b9, 0x00c1, 0x00c3,
0x00c7, 0x00cb, 0x00d1, 0x00d7, 0x00dd, 0x00e0, 0x00e6, 0x00f8,
@@ -935,15 +1019,16 @@ static const uint16_t unicode_decomp_table2[693] = {
0x2207, 0x1dc8, 0x2202, 0x1dca, 0x1dd2, 0x03f4, 0x1dd4, 0x2207,
0x1dd6, 0x2202, 0x1dd8, 0x1de0, 0x03f4, 0x1de2, 0x2207, 0x1de4,
0x2202, 0x1de6, 0x1dee, 0x03f4, 0x1df0, 0x2207, 0x1df2, 0x2202,
- 0x1df4, 0x1dfe, 0x1e00, 0x1e02, 0x1e04, 0x1e06, 0x1e08, 0x1e0e,
- 0x1e2b, 0x062d, 0x1e33, 0x1e3f, 0x062c, 0x1e4f, 0x1ebf, 0x1ecb,
- 0x1ede, 0x1ef0, 0x1f03, 0x1f05, 0x1f09, 0x1f0f, 0x1f15, 0x1f17,
- 0x1f1b, 0x1f1d, 0x1f25, 0x1f28, 0x1f2a, 0x1f30, 0x1f32, 0x30b5,
- 0x1f38, 0x1f90, 0x1fa6, 0x1faa, 0x1fac, 0x1fb1, 0x1ffe, 0x200f,
- 0x2110, 0x2120, 0x2126, 0x2220, 0x233e,
+ 0x1df4, 0x1dfe, 0x1e00, 0x1e02, 0x1e04, 0x1e06, 0x1e08, 0x1e0a,
+ 0x1e0c, 0x1e0e, 0x1e16, 0x1e39, 0x1e3d, 0x1e43, 0x1e60, 0x062d,
+ 0x1e68, 0x1e74, 0x062c, 0x1e84, 0x1ef4, 0x1f00, 0x1f13, 0x1f25,
+ 0x1f38, 0x1f3a, 0x1f3e, 0x1f44, 0x1f4a, 0x1f4c, 0x1f50, 0x1f52,
+ 0x1f5a, 0x1f5d, 0x1f5f, 0x1f65, 0x1f67, 0x30b5, 0x1f6d, 0x1fc5,
+ 0x1fdb, 0x1fdf, 0x1fe1, 0x1fe6, 0x2033, 0x2044, 0x2145, 0x2155,
+ 0x215b, 0x2255, 0x2373,
};
-static const uint8_t unicode_decomp_data[9292] = {
+static const uint8_t unicode_decomp_data[9345] = {
0x20, 0x88, 0x20, 0x84, 0x32, 0x33, 0x20, 0x81,
0x20, 0xa7, 0x31, 0x6f, 0x31, 0xd0, 0x34, 0x31,
0xd0, 0x32, 0x33, 0xd0, 0x34, 0x41, 0x80, 0x41,
@@ -1905,207 +1990,214 @@ static const uint8_t unicode_decomp_data[9292] = {
0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00,
0x1f, 0x04, 0x20, 0x05, 0x0b, 0x0c, 0x30, 0x00,
0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00,
- 0x27, 0x06, 0x00, 0x01, 0x05, 0x08, 0x2a, 0x06,
- 0x1e, 0x08, 0x03, 0x0d, 0x20, 0x19, 0x1a, 0x1b,
- 0x1c, 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a,
- 0x00, 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x44,
- 0x90, 0x77, 0x45, 0x28, 0x06, 0x2c, 0x06, 0x00,
- 0x00, 0x47, 0x06, 0x33, 0x06, 0x17, 0x10, 0x11,
- 0x12, 0x13, 0x00, 0x06, 0x0e, 0x02, 0x0f, 0x34,
- 0x06, 0x2a, 0x06, 0x2b, 0x06, 0x2e, 0x06, 0x00,
- 0x00, 0x36, 0x06, 0x00, 0x00, 0x3a, 0x06, 0x2d,
- 0x06, 0x00, 0x00, 0x4a, 0x06, 0x00, 0x00, 0x44,
- 0x06, 0x00, 0x00, 0x46, 0x06, 0x33, 0x06, 0x39,
- 0x06, 0x00, 0x00, 0x35, 0x06, 0x42, 0x06, 0x00,
- 0x00, 0x34, 0x06, 0x00, 0x00, 0x00, 0x00, 0x2e,
- 0x06, 0x00, 0x00, 0x36, 0x06, 0x00, 0x00, 0x3a,
- 0x06, 0x00, 0x00, 0xba, 0x06, 0x00, 0x00, 0x6f,
- 0x06, 0x00, 0x00, 0x28, 0x06, 0x2c, 0x06, 0x00,
- 0x00, 0x47, 0x06, 0x00, 0x00, 0x00, 0x00, 0x2d,
- 0x06, 0x37, 0x06, 0x4a, 0x06, 0x43, 0x06, 0x00,
- 0x00, 0x45, 0x06, 0x46, 0x06, 0x33, 0x06, 0x39,
- 0x06, 0x41, 0x06, 0x35, 0x06, 0x42, 0x06, 0x00,
- 0x00, 0x34, 0x06, 0x2a, 0x06, 0x2b, 0x06, 0x2e,
- 0x06, 0x00, 0x00, 0x36, 0x06, 0x38, 0x06, 0x3a,
- 0x06, 0x6e, 0x06, 0x00, 0x00, 0xa1, 0x06, 0x27,
- 0x06, 0x00, 0x01, 0x05, 0x08, 0x20, 0x21, 0x0b,
- 0x06, 0x10, 0x23, 0x2a, 0x06, 0x1a, 0x1b, 0x1c,
- 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00,
- 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x28, 0x06,
- 0x2c, 0x06, 0x2f, 0x06, 0x00, 0x00, 0x48, 0x06,
- 0x32, 0x06, 0x2d, 0x06, 0x37, 0x06, 0x4a, 0x06,
+ 0x30, 0x04, 0x3a, 0x04, 0x3e, 0x04, 0x4b, 0x04,
+ 0x4d, 0x04, 0x4e, 0x04, 0x89, 0xa6, 0x30, 0x04,
+ 0xa9, 0x26, 0x28, 0xb9, 0x7f, 0x9f, 0x00, 0x01,
+ 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0a,
+ 0x0b, 0x0e, 0x0f, 0x11, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x1a, 0x1b, 0x61, 0x26, 0x25, 0x2f,
+ 0x7b, 0x51, 0xa6, 0xb1, 0x04, 0x27, 0x06, 0x00,
+ 0x01, 0x05, 0x08, 0x2a, 0x06, 0x1e, 0x08, 0x03,
+ 0x0d, 0x20, 0x19, 0x1a, 0x1b, 0x1c, 0x09, 0x0f,
+ 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00, 0x01, 0x04,
+ 0x06, 0x0c, 0x0e, 0x10, 0x44, 0x90, 0x77, 0x45,
+ 0x28, 0x06, 0x2c, 0x06, 0x00, 0x00, 0x47, 0x06,
+ 0x33, 0x06, 0x17, 0x10, 0x11, 0x12, 0x13, 0x00,
+ 0x06, 0x0e, 0x02, 0x0f, 0x34, 0x06, 0x2a, 0x06,
+ 0x2b, 0x06, 0x2e, 0x06, 0x00, 0x00, 0x36, 0x06,
+ 0x00, 0x00, 0x3a, 0x06, 0x2d, 0x06, 0x00, 0x00,
+ 0x4a, 0x06, 0x00, 0x00, 0x44, 0x06, 0x00, 0x00,
+ 0x46, 0x06, 0x33, 0x06, 0x39, 0x06, 0x00, 0x00,
+ 0x35, 0x06, 0x42, 0x06, 0x00, 0x00, 0x34, 0x06,
+ 0x00, 0x00, 0x00, 0x00, 0x2e, 0x06, 0x00, 0x00,
+ 0x36, 0x06, 0x00, 0x00, 0x3a, 0x06, 0x00, 0x00,
+ 0xba, 0x06, 0x00, 0x00, 0x6f, 0x06, 0x00, 0x00,
+ 0x28, 0x06, 0x2c, 0x06, 0x00, 0x00, 0x47, 0x06,
+ 0x00, 0x00, 0x00, 0x00, 0x2d, 0x06, 0x37, 0x06,
+ 0x4a, 0x06, 0x43, 0x06, 0x00, 0x00, 0x45, 0x06,
+ 0x46, 0x06, 0x33, 0x06, 0x39, 0x06, 0x41, 0x06,
+ 0x35, 0x06, 0x42, 0x06, 0x00, 0x00, 0x34, 0x06,
+ 0x2a, 0x06, 0x2b, 0x06, 0x2e, 0x06, 0x00, 0x00,
+ 0x36, 0x06, 0x38, 0x06, 0x3a, 0x06, 0x6e, 0x06,
+ 0x00, 0x00, 0xa1, 0x06, 0x27, 0x06, 0x00, 0x01,
+ 0x05, 0x08, 0x20, 0x21, 0x0b, 0x06, 0x10, 0x23,
0x2a, 0x06, 0x1a, 0x1b, 0x1c, 0x09, 0x0f, 0x17,
0x0b, 0x18, 0x07, 0x0a, 0x00, 0x01, 0x04, 0x06,
- 0x0c, 0x0e, 0x10, 0x30, 0x2e, 0x30, 0x00, 0x2c,
- 0x00, 0x28, 0x00, 0x41, 0x00, 0x29, 0x00, 0x14,
- 0x30, 0x53, 0x00, 0x15, 0x30, 0x43, 0x52, 0x43,
- 0x44, 0x57, 0x5a, 0x41, 0x00, 0x48, 0x56, 0x4d,
- 0x56, 0x53, 0x44, 0x53, 0x53, 0x50, 0x50, 0x56,
- 0x57, 0x43, 0x4d, 0x43, 0x4d, 0x44, 0x4d, 0x52,
- 0x44, 0x4a, 0x4b, 0x30, 0x30, 0x00, 0x68, 0x68,
- 0x4b, 0x62, 0x57, 0x5b, 0xcc, 0x53, 0xc7, 0x30,
- 0x8c, 0x4e, 0x1a, 0x59, 0xe3, 0x89, 0x29, 0x59,
- 0xa4, 0x4e, 0x20, 0x66, 0x21, 0x71, 0x99, 0x65,
- 0x4d, 0x52, 0x8c, 0x5f, 0x8d, 0x51, 0xb0, 0x65,
- 0x1d, 0x52, 0x42, 0x7d, 0x1f, 0x75, 0xa9, 0x8c,
- 0xf0, 0x58, 0x39, 0x54, 0x14, 0x6f, 0x95, 0x62,
- 0x55, 0x63, 0x00, 0x4e, 0x09, 0x4e, 0x4a, 0x90,
- 0xe6, 0x5d, 0x2d, 0x4e, 0xf3, 0x53, 0x07, 0x63,
- 0x70, 0x8d, 0x53, 0x62, 0x81, 0x79, 0x7a, 0x7a,
- 0x08, 0x54, 0x80, 0x6e, 0x09, 0x67, 0x08, 0x67,
- 0x33, 0x75, 0x72, 0x52, 0xb6, 0x55, 0x4d, 0x91,
- 0x14, 0x30, 0x15, 0x30, 0x2c, 0x67, 0x09, 0x4e,
- 0x8c, 0x4e, 0x89, 0x5b, 0xb9, 0x70, 0x53, 0x62,
- 0xd7, 0x76, 0xdd, 0x52, 0x57, 0x65, 0x97, 0x5f,
- 0xef, 0x53, 0x30, 0x00, 0x38, 0x4e, 0x05, 0x00,
- 0x09, 0x22, 0x01, 0x60, 0x4f, 0xae, 0x4f, 0xbb,
- 0x4f, 0x02, 0x50, 0x7a, 0x50, 0x99, 0x50, 0xe7,
- 0x50, 0xcf, 0x50, 0x9e, 0x34, 0x3a, 0x06, 0x4d,
- 0x51, 0x54, 0x51, 0x64, 0x51, 0x77, 0x51, 0x1c,
- 0x05, 0xb9, 0x34, 0x67, 0x51, 0x8d, 0x51, 0x4b,
- 0x05, 0x97, 0x51, 0xa4, 0x51, 0xcc, 0x4e, 0xac,
- 0x51, 0xb5, 0x51, 0xdf, 0x91, 0xf5, 0x51, 0x03,
- 0x52, 0xdf, 0x34, 0x3b, 0x52, 0x46, 0x52, 0x72,
- 0x52, 0x77, 0x52, 0x15, 0x35, 0x02, 0x00, 0x20,
- 0x80, 0x80, 0x00, 0x08, 0x00, 0x00, 0xc7, 0x52,
- 0x00, 0x02, 0x1d, 0x33, 0x3e, 0x3f, 0x50, 0x82,
- 0x8a, 0x93, 0xac, 0xb6, 0xb8, 0xb8, 0xb8, 0x2c,
- 0x0a, 0x70, 0x70, 0xca, 0x53, 0xdf, 0x53, 0x63,
- 0x0b, 0xeb, 0x53, 0xf1, 0x53, 0x06, 0x54, 0x9e,
- 0x54, 0x38, 0x54, 0x48, 0x54, 0x68, 0x54, 0xa2,
- 0x54, 0xf6, 0x54, 0x10, 0x55, 0x53, 0x55, 0x63,
- 0x55, 0x84, 0x55, 0x84, 0x55, 0x99, 0x55, 0xab,
- 0x55, 0xb3, 0x55, 0xc2, 0x55, 0x16, 0x57, 0x06,
- 0x56, 0x17, 0x57, 0x51, 0x56, 0x74, 0x56, 0x07,
- 0x52, 0xee, 0x58, 0xce, 0x57, 0xf4, 0x57, 0x0d,
- 0x58, 0x8b, 0x57, 0x32, 0x58, 0x31, 0x58, 0xac,
- 0x58, 0xe4, 0x14, 0xf2, 0x58, 0xf7, 0x58, 0x06,
- 0x59, 0x1a, 0x59, 0x22, 0x59, 0x62, 0x59, 0xa8,
- 0x16, 0xea, 0x16, 0xec, 0x59, 0x1b, 0x5a, 0x27,
- 0x5a, 0xd8, 0x59, 0x66, 0x5a, 0xee, 0x36, 0xfc,
- 0x36, 0x08, 0x5b, 0x3e, 0x5b, 0x3e, 0x5b, 0xc8,
- 0x19, 0xc3, 0x5b, 0xd8, 0x5b, 0xe7, 0x5b, 0xf3,
- 0x5b, 0x18, 0x1b, 0xff, 0x5b, 0x06, 0x5c, 0x53,
- 0x5f, 0x22, 0x5c, 0x81, 0x37, 0x60, 0x5c, 0x6e,
- 0x5c, 0xc0, 0x5c, 0x8d, 0x5c, 0xe4, 0x1d, 0x43,
- 0x5d, 0xe6, 0x1d, 0x6e, 0x5d, 0x6b, 0x5d, 0x7c,
- 0x5d, 0xe1, 0x5d, 0xe2, 0x5d, 0x2f, 0x38, 0xfd,
- 0x5d, 0x28, 0x5e, 0x3d, 0x5e, 0x69, 0x5e, 0x62,
- 0x38, 0x83, 0x21, 0x7c, 0x38, 0xb0, 0x5e, 0xb3,
- 0x5e, 0xb6, 0x5e, 0xca, 0x5e, 0x92, 0xa3, 0xfe,
- 0x5e, 0x31, 0x23, 0x31, 0x23, 0x01, 0x82, 0x22,
- 0x5f, 0x22, 0x5f, 0xc7, 0x38, 0xb8, 0x32, 0xda,
- 0x61, 0x62, 0x5f, 0x6b, 0x5f, 0xe3, 0x38, 0x9a,
- 0x5f, 0xcd, 0x5f, 0xd7, 0x5f, 0xf9, 0x5f, 0x81,
- 0x60, 0x3a, 0x39, 0x1c, 0x39, 0x94, 0x60, 0xd4,
- 0x26, 0xc7, 0x60, 0x02, 0x02, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00,
- 0x00, 0x02, 0x08, 0x00, 0x80, 0x08, 0x00, 0x00,
- 0x08, 0x80, 0x28, 0x80, 0x02, 0x00, 0x00, 0x02,
- 0x48, 0x61, 0x00, 0x04, 0x06, 0x04, 0x32, 0x46,
- 0x6a, 0x5c, 0x67, 0x96, 0xaa, 0xae, 0xc8, 0xd3,
- 0x5d, 0x62, 0x00, 0x54, 0x77, 0xf3, 0x0c, 0x2b,
- 0x3d, 0x63, 0xfc, 0x62, 0x68, 0x63, 0x83, 0x63,
- 0xe4, 0x63, 0xf1, 0x2b, 0x22, 0x64, 0xc5, 0x63,
- 0xa9, 0x63, 0x2e, 0x3a, 0x69, 0x64, 0x7e, 0x64,
- 0x9d, 0x64, 0x77, 0x64, 0x6c, 0x3a, 0x4f, 0x65,
- 0x6c, 0x65, 0x0a, 0x30, 0xe3, 0x65, 0xf8, 0x66,
- 0x49, 0x66, 0x19, 0x3b, 0x91, 0x66, 0x08, 0x3b,
- 0xe4, 0x3a, 0x92, 0x51, 0x95, 0x51, 0x00, 0x67,
- 0x9c, 0x66, 0xad, 0x80, 0xd9, 0x43, 0x17, 0x67,
- 0x1b, 0x67, 0x21, 0x67, 0x5e, 0x67, 0x53, 0x67,
- 0xc3, 0x33, 0x49, 0x3b, 0xfa, 0x67, 0x85, 0x67,
- 0x52, 0x68, 0x85, 0x68, 0x6d, 0x34, 0x8e, 0x68,
- 0x1f, 0x68, 0x14, 0x69, 0x9d, 0x3b, 0x42, 0x69,
- 0xa3, 0x69, 0xea, 0x69, 0xa8, 0x6a, 0xa3, 0x36,
- 0xdb, 0x6a, 0x18, 0x3c, 0x21, 0x6b, 0xa7, 0x38,
- 0x54, 0x6b, 0x4e, 0x3c, 0x72, 0x6b, 0x9f, 0x6b,
- 0xba, 0x6b, 0xbb, 0x6b, 0x8d, 0x3a, 0x0b, 0x1d,
- 0xfa, 0x3a, 0x4e, 0x6c, 0xbc, 0x3c, 0xbf, 0x6c,
- 0xcd, 0x6c, 0x67, 0x6c, 0x16, 0x6d, 0x3e, 0x6d,
- 0x77, 0x6d, 0x41, 0x6d, 0x69, 0x6d, 0x78, 0x6d,
- 0x85, 0x6d, 0x1e, 0x3d, 0x34, 0x6d, 0x2f, 0x6e,
- 0x6e, 0x6e, 0x33, 0x3d, 0xcb, 0x6e, 0xc7, 0x6e,
- 0xd1, 0x3e, 0xf9, 0x6d, 0x6e, 0x6f, 0x5e, 0x3f,
- 0x8e, 0x3f, 0xc6, 0x6f, 0x39, 0x70, 0x1e, 0x70,
- 0x1b, 0x70, 0x96, 0x3d, 0x4a, 0x70, 0x7d, 0x70,
- 0x77, 0x70, 0xad, 0x70, 0x25, 0x05, 0x45, 0x71,
- 0x63, 0x42, 0x9c, 0x71, 0xab, 0x43, 0x28, 0x72,
- 0x35, 0x72, 0x50, 0x72, 0x08, 0x46, 0x80, 0x72,
- 0x95, 0x72, 0x35, 0x47, 0x02, 0x20, 0x00, 0x00,
- 0x20, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00,
- 0x00, 0x02, 0x02, 0x80, 0x8a, 0x00, 0x00, 0x20,
- 0x00, 0x08, 0x0a, 0x00, 0x80, 0x88, 0x80, 0x20,
- 0x14, 0x48, 0x7a, 0x73, 0x8b, 0x73, 0xac, 0x3e,
- 0xa5, 0x73, 0xb8, 0x3e, 0xb8, 0x3e, 0x47, 0x74,
- 0x5c, 0x74, 0x71, 0x74, 0x85, 0x74, 0xca, 0x74,
- 0x1b, 0x3f, 0x24, 0x75, 0x36, 0x4c, 0x3e, 0x75,
- 0x92, 0x4c, 0x70, 0x75, 0x9f, 0x21, 0x10, 0x76,
- 0xa1, 0x4f, 0xb8, 0x4f, 0x44, 0x50, 0xfc, 0x3f,
- 0x08, 0x40, 0xf4, 0x76, 0xf3, 0x50, 0xf2, 0x50,
- 0x19, 0x51, 0x33, 0x51, 0x1e, 0x77, 0x1f, 0x77,
- 0x1f, 0x77, 0x4a, 0x77, 0x39, 0x40, 0x8b, 0x77,
- 0x46, 0x40, 0x96, 0x40, 0x1d, 0x54, 0x4e, 0x78,
- 0x8c, 0x78, 0xcc, 0x78, 0xe3, 0x40, 0x26, 0x56,
- 0x56, 0x79, 0x9a, 0x56, 0xc5, 0x56, 0x8f, 0x79,
- 0xeb, 0x79, 0x2f, 0x41, 0x40, 0x7a, 0x4a, 0x7a,
- 0x4f, 0x7a, 0x7c, 0x59, 0xa7, 0x5a, 0xa7, 0x5a,
- 0xee, 0x7a, 0x02, 0x42, 0xab, 0x5b, 0xc6, 0x7b,
- 0xc9, 0x7b, 0x27, 0x42, 0x80, 0x5c, 0xd2, 0x7c,
- 0xa0, 0x42, 0xe8, 0x7c, 0xe3, 0x7c, 0x00, 0x7d,
- 0x86, 0x5f, 0x63, 0x7d, 0x01, 0x43, 0xc7, 0x7d,
- 0x02, 0x7e, 0x45, 0x7e, 0x34, 0x43, 0x28, 0x62,
- 0x47, 0x62, 0x59, 0x43, 0xd9, 0x62, 0x7a, 0x7f,
- 0x3e, 0x63, 0x95, 0x7f, 0xfa, 0x7f, 0x05, 0x80,
- 0xda, 0x64, 0x23, 0x65, 0x60, 0x80, 0xa8, 0x65,
- 0x70, 0x80, 0x5f, 0x33, 0xd5, 0x43, 0xb2, 0x80,
- 0x03, 0x81, 0x0b, 0x44, 0x3e, 0x81, 0xb5, 0x5a,
- 0xa7, 0x67, 0xb5, 0x67, 0x93, 0x33, 0x9c, 0x33,
- 0x01, 0x82, 0x04, 0x82, 0x9e, 0x8f, 0x6b, 0x44,
- 0x91, 0x82, 0x8b, 0x82, 0x9d, 0x82, 0xb3, 0x52,
- 0xb1, 0x82, 0xb3, 0x82, 0xbd, 0x82, 0xe6, 0x82,
- 0x3c, 0x6b, 0xe5, 0x82, 0x1d, 0x83, 0x63, 0x83,
- 0xad, 0x83, 0x23, 0x83, 0xbd, 0x83, 0xe7, 0x83,
- 0x57, 0x84, 0x53, 0x83, 0xca, 0x83, 0xcc, 0x83,
- 0xdc, 0x83, 0x36, 0x6c, 0x6b, 0x6d, 0x02, 0x00,
- 0x00, 0x20, 0x22, 0x2a, 0xa0, 0x0a, 0x00, 0x20,
- 0x80, 0x28, 0x00, 0xa8, 0x20, 0x20, 0x00, 0x02,
- 0x80, 0x22, 0x02, 0x8a, 0x08, 0x00, 0xaa, 0x00,
- 0x00, 0x00, 0x02, 0x00, 0x00, 0x28, 0xd5, 0x6c,
- 0x2b, 0x45, 0xf1, 0x84, 0xf3, 0x84, 0x16, 0x85,
- 0xca, 0x73, 0x64, 0x85, 0x2c, 0x6f, 0x5d, 0x45,
- 0x61, 0x45, 0xb1, 0x6f, 0xd2, 0x70, 0x6b, 0x45,
- 0x50, 0x86, 0x5c, 0x86, 0x67, 0x86, 0x69, 0x86,
- 0xa9, 0x86, 0x88, 0x86, 0x0e, 0x87, 0xe2, 0x86,
- 0x79, 0x87, 0x28, 0x87, 0x6b, 0x87, 0x86, 0x87,
- 0xd7, 0x45, 0xe1, 0x87, 0x01, 0x88, 0xf9, 0x45,
- 0x60, 0x88, 0x63, 0x88, 0x67, 0x76, 0xd7, 0x88,
- 0xde, 0x88, 0x35, 0x46, 0xfa, 0x88, 0xbb, 0x34,
- 0xae, 0x78, 0x66, 0x79, 0xbe, 0x46, 0xc7, 0x46,
- 0xa0, 0x8a, 0xed, 0x8a, 0x8a, 0x8b, 0x55, 0x8c,
- 0xa8, 0x7c, 0xab, 0x8c, 0xc1, 0x8c, 0x1b, 0x8d,
- 0x77, 0x8d, 0x2f, 0x7f, 0x04, 0x08, 0xcb, 0x8d,
- 0xbc, 0x8d, 0xf0, 0x8d, 0xde, 0x08, 0xd4, 0x8e,
- 0x38, 0x8f, 0xd2, 0x85, 0xed, 0x85, 0x94, 0x90,
- 0xf1, 0x90, 0x11, 0x91, 0x2e, 0x87, 0x1b, 0x91,
- 0x38, 0x92, 0xd7, 0x92, 0xd8, 0x92, 0x7c, 0x92,
- 0xf9, 0x93, 0x15, 0x94, 0xfa, 0x8b, 0x8b, 0x95,
- 0x95, 0x49, 0xb7, 0x95, 0x77, 0x8d, 0xe6, 0x49,
- 0xc3, 0x96, 0xb2, 0x5d, 0x23, 0x97, 0x45, 0x91,
- 0x1a, 0x92, 0x6e, 0x4a, 0x76, 0x4a, 0xe0, 0x97,
- 0x0a, 0x94, 0xb2, 0x4a, 0x96, 0x94, 0x0b, 0x98,
- 0x0b, 0x98, 0x29, 0x98, 0xb6, 0x95, 0xe2, 0x98,
- 0x33, 0x4b, 0x29, 0x99, 0xa7, 0x99, 0xc2, 0x99,
- 0xfe, 0x99, 0xce, 0x4b, 0x30, 0x9b, 0x12, 0x9b,
- 0x40, 0x9c, 0xfd, 0x9c, 0xce, 0x4c, 0xed, 0x4c,
- 0x67, 0x9d, 0xce, 0xa0, 0xf8, 0x4c, 0x05, 0xa1,
- 0x0e, 0xa2, 0x91, 0xa2, 0xbb, 0x9e, 0x56, 0x4d,
- 0xf9, 0x9e, 0xfe, 0x9e, 0x05, 0x9f, 0x0f, 0x9f,
- 0x16, 0x9f, 0x3b, 0x9f, 0x00, 0xa6, 0x02, 0x88,
- 0xa0, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x28,
- 0x00, 0x08, 0xa0, 0x80, 0xa0, 0x80, 0x00, 0x80,
- 0x80, 0x00, 0x0a, 0x88, 0x80, 0x00, 0x80, 0x00,
- 0x20, 0x2a, 0x00, 0x80,
+ 0x0c, 0x0e, 0x10, 0x28, 0x06, 0x2c, 0x06, 0x2f,
+ 0x06, 0x00, 0x00, 0x48, 0x06, 0x32, 0x06, 0x2d,
+ 0x06, 0x37, 0x06, 0x4a, 0x06, 0x2a, 0x06, 0x1a,
+ 0x1b, 0x1c, 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07,
+ 0x0a, 0x00, 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10,
+ 0x30, 0x2e, 0x30, 0x00, 0x2c, 0x00, 0x28, 0x00,
+ 0x41, 0x00, 0x29, 0x00, 0x14, 0x30, 0x53, 0x00,
+ 0x15, 0x30, 0x43, 0x52, 0x43, 0x44, 0x57, 0x5a,
+ 0x41, 0x00, 0x48, 0x56, 0x4d, 0x56, 0x53, 0x44,
+ 0x53, 0x53, 0x50, 0x50, 0x56, 0x57, 0x43, 0x4d,
+ 0x43, 0x4d, 0x44, 0x4d, 0x52, 0x44, 0x4a, 0x4b,
+ 0x30, 0x30, 0x00, 0x68, 0x68, 0x4b, 0x62, 0x57,
+ 0x5b, 0xcc, 0x53, 0xc7, 0x30, 0x8c, 0x4e, 0x1a,
+ 0x59, 0xe3, 0x89, 0x29, 0x59, 0xa4, 0x4e, 0x20,
+ 0x66, 0x21, 0x71, 0x99, 0x65, 0x4d, 0x52, 0x8c,
+ 0x5f, 0x8d, 0x51, 0xb0, 0x65, 0x1d, 0x52, 0x42,
+ 0x7d, 0x1f, 0x75, 0xa9, 0x8c, 0xf0, 0x58, 0x39,
+ 0x54, 0x14, 0x6f, 0x95, 0x62, 0x55, 0x63, 0x00,
+ 0x4e, 0x09, 0x4e, 0x4a, 0x90, 0xe6, 0x5d, 0x2d,
+ 0x4e, 0xf3, 0x53, 0x07, 0x63, 0x70, 0x8d, 0x53,
+ 0x62, 0x81, 0x79, 0x7a, 0x7a, 0x08, 0x54, 0x80,
+ 0x6e, 0x09, 0x67, 0x08, 0x67, 0x33, 0x75, 0x72,
+ 0x52, 0xb6, 0x55, 0x4d, 0x91, 0x14, 0x30, 0x15,
+ 0x30, 0x2c, 0x67, 0x09, 0x4e, 0x8c, 0x4e, 0x89,
+ 0x5b, 0xb9, 0x70, 0x53, 0x62, 0xd7, 0x76, 0xdd,
+ 0x52, 0x57, 0x65, 0x97, 0x5f, 0xef, 0x53, 0x30,
+ 0x00, 0x38, 0x4e, 0x05, 0x00, 0x09, 0x22, 0x01,
+ 0x60, 0x4f, 0xae, 0x4f, 0xbb, 0x4f, 0x02, 0x50,
+ 0x7a, 0x50, 0x99, 0x50, 0xe7, 0x50, 0xcf, 0x50,
+ 0x9e, 0x34, 0x3a, 0x06, 0x4d, 0x51, 0x54, 0x51,
+ 0x64, 0x51, 0x77, 0x51, 0x1c, 0x05, 0xb9, 0x34,
+ 0x67, 0x51, 0x8d, 0x51, 0x4b, 0x05, 0x97, 0x51,
+ 0xa4, 0x51, 0xcc, 0x4e, 0xac, 0x51, 0xb5, 0x51,
+ 0xdf, 0x91, 0xf5, 0x51, 0x03, 0x52, 0xdf, 0x34,
+ 0x3b, 0x52, 0x46, 0x52, 0x72, 0x52, 0x77, 0x52,
+ 0x15, 0x35, 0x02, 0x00, 0x20, 0x80, 0x80, 0x00,
+ 0x08, 0x00, 0x00, 0xc7, 0x52, 0x00, 0x02, 0x1d,
+ 0x33, 0x3e, 0x3f, 0x50, 0x82, 0x8a, 0x93, 0xac,
+ 0xb6, 0xb8, 0xb8, 0xb8, 0x2c, 0x0a, 0x70, 0x70,
+ 0xca, 0x53, 0xdf, 0x53, 0x63, 0x0b, 0xeb, 0x53,
+ 0xf1, 0x53, 0x06, 0x54, 0x9e, 0x54, 0x38, 0x54,
+ 0x48, 0x54, 0x68, 0x54, 0xa2, 0x54, 0xf6, 0x54,
+ 0x10, 0x55, 0x53, 0x55, 0x63, 0x55, 0x84, 0x55,
+ 0x84, 0x55, 0x99, 0x55, 0xab, 0x55, 0xb3, 0x55,
+ 0xc2, 0x55, 0x16, 0x57, 0x06, 0x56, 0x17, 0x57,
+ 0x51, 0x56, 0x74, 0x56, 0x07, 0x52, 0xee, 0x58,
+ 0xce, 0x57, 0xf4, 0x57, 0x0d, 0x58, 0x8b, 0x57,
+ 0x32, 0x58, 0x31, 0x58, 0xac, 0x58, 0xe4, 0x14,
+ 0xf2, 0x58, 0xf7, 0x58, 0x06, 0x59, 0x1a, 0x59,
+ 0x22, 0x59, 0x62, 0x59, 0xa8, 0x16, 0xea, 0x16,
+ 0xec, 0x59, 0x1b, 0x5a, 0x27, 0x5a, 0xd8, 0x59,
+ 0x66, 0x5a, 0xee, 0x36, 0xfc, 0x36, 0x08, 0x5b,
+ 0x3e, 0x5b, 0x3e, 0x5b, 0xc8, 0x19, 0xc3, 0x5b,
+ 0xd8, 0x5b, 0xe7, 0x5b, 0xf3, 0x5b, 0x18, 0x1b,
+ 0xff, 0x5b, 0x06, 0x5c, 0x53, 0x5f, 0x22, 0x5c,
+ 0x81, 0x37, 0x60, 0x5c, 0x6e, 0x5c, 0xc0, 0x5c,
+ 0x8d, 0x5c, 0xe4, 0x1d, 0x43, 0x5d, 0xe6, 0x1d,
+ 0x6e, 0x5d, 0x6b, 0x5d, 0x7c, 0x5d, 0xe1, 0x5d,
+ 0xe2, 0x5d, 0x2f, 0x38, 0xfd, 0x5d, 0x28, 0x5e,
+ 0x3d, 0x5e, 0x69, 0x5e, 0x62, 0x38, 0x83, 0x21,
+ 0x7c, 0x38, 0xb0, 0x5e, 0xb3, 0x5e, 0xb6, 0x5e,
+ 0xca, 0x5e, 0x92, 0xa3, 0xfe, 0x5e, 0x31, 0x23,
+ 0x31, 0x23, 0x01, 0x82, 0x22, 0x5f, 0x22, 0x5f,
+ 0xc7, 0x38, 0xb8, 0x32, 0xda, 0x61, 0x62, 0x5f,
+ 0x6b, 0x5f, 0xe3, 0x38, 0x9a, 0x5f, 0xcd, 0x5f,
+ 0xd7, 0x5f, 0xf9, 0x5f, 0x81, 0x60, 0x3a, 0x39,
+ 0x1c, 0x39, 0x94, 0x60, 0xd4, 0x26, 0xc7, 0x60,
+ 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, 0x02, 0x08,
+ 0x00, 0x80, 0x08, 0x00, 0x00, 0x08, 0x80, 0x28,
+ 0x80, 0x02, 0x00, 0x00, 0x02, 0x48, 0x61, 0x00,
+ 0x04, 0x06, 0x04, 0x32, 0x46, 0x6a, 0x5c, 0x67,
+ 0x96, 0xaa, 0xae, 0xc8, 0xd3, 0x5d, 0x62, 0x00,
+ 0x54, 0x77, 0xf3, 0x0c, 0x2b, 0x3d, 0x63, 0xfc,
+ 0x62, 0x68, 0x63, 0x83, 0x63, 0xe4, 0x63, 0xf1,
+ 0x2b, 0x22, 0x64, 0xc5, 0x63, 0xa9, 0x63, 0x2e,
+ 0x3a, 0x69, 0x64, 0x7e, 0x64, 0x9d, 0x64, 0x77,
+ 0x64, 0x6c, 0x3a, 0x4f, 0x65, 0x6c, 0x65, 0x0a,
+ 0x30, 0xe3, 0x65, 0xf8, 0x66, 0x49, 0x66, 0x19,
+ 0x3b, 0x91, 0x66, 0x08, 0x3b, 0xe4, 0x3a, 0x92,
+ 0x51, 0x95, 0x51, 0x00, 0x67, 0x9c, 0x66, 0xad,
+ 0x80, 0xd9, 0x43, 0x17, 0x67, 0x1b, 0x67, 0x21,
+ 0x67, 0x5e, 0x67, 0x53, 0x67, 0xc3, 0x33, 0x49,
+ 0x3b, 0xfa, 0x67, 0x85, 0x67, 0x52, 0x68, 0x85,
+ 0x68, 0x6d, 0x34, 0x8e, 0x68, 0x1f, 0x68, 0x14,
+ 0x69, 0x9d, 0x3b, 0x42, 0x69, 0xa3, 0x69, 0xea,
+ 0x69, 0xa8, 0x6a, 0xa3, 0x36, 0xdb, 0x6a, 0x18,
+ 0x3c, 0x21, 0x6b, 0xa7, 0x38, 0x54, 0x6b, 0x4e,
+ 0x3c, 0x72, 0x6b, 0x9f, 0x6b, 0xba, 0x6b, 0xbb,
+ 0x6b, 0x8d, 0x3a, 0x0b, 0x1d, 0xfa, 0x3a, 0x4e,
+ 0x6c, 0xbc, 0x3c, 0xbf, 0x6c, 0xcd, 0x6c, 0x67,
+ 0x6c, 0x16, 0x6d, 0x3e, 0x6d, 0x77, 0x6d, 0x41,
+ 0x6d, 0x69, 0x6d, 0x78, 0x6d, 0x85, 0x6d, 0x1e,
+ 0x3d, 0x34, 0x6d, 0x2f, 0x6e, 0x6e, 0x6e, 0x33,
+ 0x3d, 0xcb, 0x6e, 0xc7, 0x6e, 0xd1, 0x3e, 0xf9,
+ 0x6d, 0x6e, 0x6f, 0x5e, 0x3f, 0x8e, 0x3f, 0xc6,
+ 0x6f, 0x39, 0x70, 0x1e, 0x70, 0x1b, 0x70, 0x96,
+ 0x3d, 0x4a, 0x70, 0x7d, 0x70, 0x77, 0x70, 0xad,
+ 0x70, 0x25, 0x05, 0x45, 0x71, 0x63, 0x42, 0x9c,
+ 0x71, 0xab, 0x43, 0x28, 0x72, 0x35, 0x72, 0x50,
+ 0x72, 0x08, 0x46, 0x80, 0x72, 0x95, 0x72, 0x35,
+ 0x47, 0x02, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x02, 0x02,
+ 0x80, 0x8a, 0x00, 0x00, 0x20, 0x00, 0x08, 0x0a,
+ 0x00, 0x80, 0x88, 0x80, 0x20, 0x14, 0x48, 0x7a,
+ 0x73, 0x8b, 0x73, 0xac, 0x3e, 0xa5, 0x73, 0xb8,
+ 0x3e, 0xb8, 0x3e, 0x47, 0x74, 0x5c, 0x74, 0x71,
+ 0x74, 0x85, 0x74, 0xca, 0x74, 0x1b, 0x3f, 0x24,
+ 0x75, 0x36, 0x4c, 0x3e, 0x75, 0x92, 0x4c, 0x70,
+ 0x75, 0x9f, 0x21, 0x10, 0x76, 0xa1, 0x4f, 0xb8,
+ 0x4f, 0x44, 0x50, 0xfc, 0x3f, 0x08, 0x40, 0xf4,
+ 0x76, 0xf3, 0x50, 0xf2, 0x50, 0x19, 0x51, 0x33,
+ 0x51, 0x1e, 0x77, 0x1f, 0x77, 0x1f, 0x77, 0x4a,
+ 0x77, 0x39, 0x40, 0x8b, 0x77, 0x46, 0x40, 0x96,
+ 0x40, 0x1d, 0x54, 0x4e, 0x78, 0x8c, 0x78, 0xcc,
+ 0x78, 0xe3, 0x40, 0x26, 0x56, 0x56, 0x79, 0x9a,
+ 0x56, 0xc5, 0x56, 0x8f, 0x79, 0xeb, 0x79, 0x2f,
+ 0x41, 0x40, 0x7a, 0x4a, 0x7a, 0x4f, 0x7a, 0x7c,
+ 0x59, 0xa7, 0x5a, 0xa7, 0x5a, 0xee, 0x7a, 0x02,
+ 0x42, 0xab, 0x5b, 0xc6, 0x7b, 0xc9, 0x7b, 0x27,
+ 0x42, 0x80, 0x5c, 0xd2, 0x7c, 0xa0, 0x42, 0xe8,
+ 0x7c, 0xe3, 0x7c, 0x00, 0x7d, 0x86, 0x5f, 0x63,
+ 0x7d, 0x01, 0x43, 0xc7, 0x7d, 0x02, 0x7e, 0x45,
+ 0x7e, 0x34, 0x43, 0x28, 0x62, 0x47, 0x62, 0x59,
+ 0x43, 0xd9, 0x62, 0x7a, 0x7f, 0x3e, 0x63, 0x95,
+ 0x7f, 0xfa, 0x7f, 0x05, 0x80, 0xda, 0x64, 0x23,
+ 0x65, 0x60, 0x80, 0xa8, 0x65, 0x70, 0x80, 0x5f,
+ 0x33, 0xd5, 0x43, 0xb2, 0x80, 0x03, 0x81, 0x0b,
+ 0x44, 0x3e, 0x81, 0xb5, 0x5a, 0xa7, 0x67, 0xb5,
+ 0x67, 0x93, 0x33, 0x9c, 0x33, 0x01, 0x82, 0x04,
+ 0x82, 0x9e, 0x8f, 0x6b, 0x44, 0x91, 0x82, 0x8b,
+ 0x82, 0x9d, 0x82, 0xb3, 0x52, 0xb1, 0x82, 0xb3,
+ 0x82, 0xbd, 0x82, 0xe6, 0x82, 0x3c, 0x6b, 0xe5,
+ 0x82, 0x1d, 0x83, 0x63, 0x83, 0xad, 0x83, 0x23,
+ 0x83, 0xbd, 0x83, 0xe7, 0x83, 0x57, 0x84, 0x53,
+ 0x83, 0xca, 0x83, 0xcc, 0x83, 0xdc, 0x83, 0x36,
+ 0x6c, 0x6b, 0x6d, 0x02, 0x00, 0x00, 0x20, 0x22,
+ 0x2a, 0xa0, 0x0a, 0x00, 0x20, 0x80, 0x28, 0x00,
+ 0xa8, 0x20, 0x20, 0x00, 0x02, 0x80, 0x22, 0x02,
+ 0x8a, 0x08, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x28, 0xd5, 0x6c, 0x2b, 0x45, 0xf1,
+ 0x84, 0xf3, 0x84, 0x16, 0x85, 0xca, 0x73, 0x64,
+ 0x85, 0x2c, 0x6f, 0x5d, 0x45, 0x61, 0x45, 0xb1,
+ 0x6f, 0xd2, 0x70, 0x6b, 0x45, 0x50, 0x86, 0x5c,
+ 0x86, 0x67, 0x86, 0x69, 0x86, 0xa9, 0x86, 0x88,
+ 0x86, 0x0e, 0x87, 0xe2, 0x86, 0x79, 0x87, 0x28,
+ 0x87, 0x6b, 0x87, 0x86, 0x87, 0xd7, 0x45, 0xe1,
+ 0x87, 0x01, 0x88, 0xf9, 0x45, 0x60, 0x88, 0x63,
+ 0x88, 0x67, 0x76, 0xd7, 0x88, 0xde, 0x88, 0x35,
+ 0x46, 0xfa, 0x88, 0xbb, 0x34, 0xae, 0x78, 0x66,
+ 0x79, 0xbe, 0x46, 0xc7, 0x46, 0xa0, 0x8a, 0xed,
+ 0x8a, 0x8a, 0x8b, 0x55, 0x8c, 0xa8, 0x7c, 0xab,
+ 0x8c, 0xc1, 0x8c, 0x1b, 0x8d, 0x77, 0x8d, 0x2f,
+ 0x7f, 0x04, 0x08, 0xcb, 0x8d, 0xbc, 0x8d, 0xf0,
+ 0x8d, 0xde, 0x08, 0xd4, 0x8e, 0x38, 0x8f, 0xd2,
+ 0x85, 0xed, 0x85, 0x94, 0x90, 0xf1, 0x90, 0x11,
+ 0x91, 0x2e, 0x87, 0x1b, 0x91, 0x38, 0x92, 0xd7,
+ 0x92, 0xd8, 0x92, 0x7c, 0x92, 0xf9, 0x93, 0x15,
+ 0x94, 0xfa, 0x8b, 0x8b, 0x95, 0x95, 0x49, 0xb7,
+ 0x95, 0x77, 0x8d, 0xe6, 0x49, 0xc3, 0x96, 0xb2,
+ 0x5d, 0x23, 0x97, 0x45, 0x91, 0x1a, 0x92, 0x6e,
+ 0x4a, 0x76, 0x4a, 0xe0, 0x97, 0x0a, 0x94, 0xb2,
+ 0x4a, 0x96, 0x94, 0x0b, 0x98, 0x0b, 0x98, 0x29,
+ 0x98, 0xb6, 0x95, 0xe2, 0x98, 0x33, 0x4b, 0x29,
+ 0x99, 0xa7, 0x99, 0xc2, 0x99, 0xfe, 0x99, 0xce,
+ 0x4b, 0x30, 0x9b, 0x12, 0x9b, 0x40, 0x9c, 0xfd,
+ 0x9c, 0xce, 0x4c, 0xed, 0x4c, 0x67, 0x9d, 0xce,
+ 0xa0, 0xf8, 0x4c, 0x05, 0xa1, 0x0e, 0xa2, 0x91,
+ 0xa2, 0xbb, 0x9e, 0x56, 0x4d, 0xf9, 0x9e, 0xfe,
+ 0x9e, 0x05, 0x9f, 0x0f, 0x9f, 0x16, 0x9f, 0x3b,
+ 0x9f, 0x00, 0xa6, 0x02, 0x88, 0xa0, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x28, 0x00, 0x08, 0xa0,
+ 0x80, 0xa0, 0x80, 0x00, 0x80, 0x80, 0x00, 0x0a,
+ 0x88, 0x80, 0x00, 0x80, 0x00, 0x20, 0x2a, 0x00,
+ 0x80,
};
static const uint16_t unicode_comp_table[945] = {
@@ -2313,7 +2405,7 @@ static const char unicode_gc_name_table[] =
"C,Other" "\0"
;
-static const uint8_t unicode_gc_table[3897] = {
+static const uint8_t unicode_gc_table[3948] = {
0xfa, 0x18, 0x17, 0x56, 0x0d, 0x56, 0x12, 0x13,
0x16, 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02, 0x36,
0x4c, 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13, 0x0e,
@@ -2399,409 +2491,415 @@ static const uint8_t unicode_gc_table[3897] = {
0x85, 0x20, 0x06, 0x05, 0x07, 0x06, 0x87, 0x00,
0x06, 0x27, 0x00, 0x27, 0x26, 0xc0, 0x27, 0xa0,
0x25, 0x00, 0x25, 0x26, 0x20, 0xe9, 0x02, 0x00,
- 0x25, 0xe0, 0x05, 0x26, 0x27, 0xe5, 0x01, 0x00,
- 0x45, 0x00, 0xe5, 0x21, 0x26, 0x05, 0x47, 0x66,
- 0x00, 0x47, 0x00, 0x47, 0x06, 0x05, 0x0f, 0x60,
- 0x45, 0x07, 0xcb, 0x45, 0x26, 0x20, 0xe9, 0x02,
- 0xeb, 0x01, 0x0f, 0xa5, 0x00, 0x06, 0x27, 0x00,
- 0xe5, 0x0a, 0x40, 0xe5, 0x10, 0x00, 0xe5, 0x01,
- 0x00, 0x05, 0x20, 0xc5, 0x40, 0x06, 0x60, 0x47,
- 0x46, 0x00, 0x06, 0x00, 0xe7, 0x00, 0xa0, 0xe9,
- 0x02, 0x20, 0x27, 0x16, 0xe0, 0x04, 0xe5, 0x28,
- 0x06, 0x25, 0xc6, 0x60, 0x0d, 0xa5, 0x04, 0xe6,
- 0x00, 0x16, 0xe9, 0x02, 0x36, 0xe0, 0x1d, 0x25,
- 0x00, 0x05, 0x00, 0x85, 0x00, 0xe5, 0x10, 0x00,
- 0x05, 0x00, 0xe5, 0x02, 0x06, 0x25, 0xe6, 0x01,
- 0x05, 0x20, 0x85, 0x00, 0x04, 0x00, 0xa6, 0x20,
- 0xe9, 0x02, 0x20, 0x65, 0xe0, 0x18, 0x05, 0x4f,
- 0xf6, 0x07, 0x0f, 0x16, 0x4f, 0x26, 0xaf, 0xe9,
- 0x02, 0xeb, 0x02, 0x0f, 0x06, 0x0f, 0x06, 0x0f,
- 0x06, 0x12, 0x13, 0x12, 0x13, 0x27, 0xe5, 0x00,
- 0x00, 0xe5, 0x1c, 0x60, 0xe6, 0x06, 0x07, 0x86,
- 0x16, 0x26, 0x85, 0xe6, 0x03, 0x00, 0xe6, 0x1c,
- 0x00, 0xef, 0x00, 0x06, 0xaf, 0x00, 0x2f, 0x96,
- 0x6f, 0x36, 0xe0, 0x1d, 0xe5, 0x23, 0x27, 0x66,
- 0x07, 0xa6, 0x07, 0x26, 0x27, 0x26, 0x05, 0xe9,
- 0x02, 0xb6, 0xa5, 0x27, 0x26, 0x65, 0x46, 0x05,
- 0x47, 0x25, 0xc7, 0x45, 0x66, 0xe5, 0x05, 0x06,
- 0x27, 0x26, 0xa7, 0x06, 0x05, 0x07, 0xe9, 0x02,
- 0x47, 0x06, 0x2f, 0xe1, 0x1e, 0x00, 0x01, 0x80,
- 0x01, 0x20, 0xe2, 0x23, 0x16, 0x04, 0x42, 0xe5,
- 0x80, 0xc1, 0x00, 0x65, 0x20, 0xc5, 0x00, 0x05,
- 0x00, 0x65, 0x20, 0xe5, 0x21, 0x00, 0x65, 0x20,
- 0xe5, 0x19, 0x00, 0x65, 0x20, 0xc5, 0x00, 0x05,
- 0x00, 0x65, 0x20, 0xe5, 0x07, 0x00, 0xe5, 0x31,
- 0x00, 0x65, 0x20, 0xe5, 0x3b, 0x20, 0x46, 0xf6,
- 0x01, 0xeb, 0x0c, 0x40, 0xe5, 0x08, 0xef, 0x02,
- 0xa0, 0xe1, 0x4e, 0x20, 0xa2, 0x20, 0x11, 0xe5,
- 0x81, 0xe4, 0x0f, 0x16, 0xe5, 0x09, 0x17, 0xe5,
- 0x12, 0x12, 0x13, 0x40, 0xe5, 0x43, 0x56, 0x4a,
- 0xe5, 0x00, 0xc0, 0xe5, 0x0a, 0x46, 0x07, 0xe0,
- 0x01, 0xe5, 0x0b, 0x26, 0x07, 0x36, 0xe0, 0x01,
- 0xe5, 0x0a, 0x26, 0xe0, 0x04, 0xe5, 0x05, 0x00,
- 0x45, 0x00, 0x26, 0xe0, 0x04, 0xe5, 0x2c, 0x26,
- 0x07, 0xc6, 0xe7, 0x00, 0x06, 0x27, 0xe6, 0x03,
- 0x56, 0x04, 0x56, 0x0d, 0x05, 0x06, 0x20, 0xe9,
- 0x02, 0xa0, 0xeb, 0x02, 0xa0, 0xb6, 0x11, 0x76,
- 0x46, 0x1b, 0x06, 0xe9, 0x02, 0xa0, 0xe5, 0x1b,
- 0x04, 0xe5, 0x2d, 0xc0, 0x85, 0x26, 0xe5, 0x1a,
- 0x06, 0x05, 0x80, 0xe5, 0x3e, 0xe0, 0x02, 0xe5,
- 0x17, 0x00, 0x46, 0x67, 0x26, 0x47, 0x60, 0x27,
- 0x06, 0xa7, 0x46, 0x60, 0x0f, 0x40, 0x36, 0xe9,
- 0x02, 0xe5, 0x16, 0x20, 0x85, 0xe0, 0x03, 0xe5,
- 0x24, 0x60, 0xe5, 0x12, 0xa0, 0xe9, 0x02, 0x0b,
- 0x40, 0xef, 0x1a, 0xe5, 0x0f, 0x26, 0x27, 0x06,
- 0x20, 0x36, 0xe5, 0x2d, 0x07, 0x06, 0x07, 0xc6,
- 0x00, 0x06, 0x07, 0x06, 0x27, 0xe6, 0x00, 0xa7,
- 0xe6, 0x02, 0x20, 0x06, 0xe9, 0x02, 0xa0, 0xe9,
- 0x02, 0xa0, 0xd6, 0x04, 0xb6, 0x20, 0xe6, 0x06,
- 0x08, 0xe6, 0x08, 0xe0, 0x29, 0x66, 0x07, 0xe5,
- 0x27, 0x06, 0x07, 0x86, 0x07, 0x06, 0x87, 0x06,
- 0x27, 0xe5, 0x00, 0x40, 0xe9, 0x02, 0xd6, 0xef,
- 0x02, 0xe6, 0x01, 0xef, 0x01, 0x36, 0x00, 0x26,
- 0x07, 0xe5, 0x16, 0x07, 0x66, 0x27, 0x26, 0x07,
- 0x46, 0x25, 0xe9, 0x02, 0xe5, 0x24, 0x06, 0x07,
- 0x26, 0x47, 0x06, 0x07, 0x46, 0x27, 0xe0, 0x00,
- 0x76, 0xe5, 0x1c, 0xe7, 0x00, 0xe6, 0x00, 0x27,
- 0x26, 0x40, 0x96, 0xe9, 0x02, 0x40, 0x45, 0xe9,
- 0x02, 0xe5, 0x16, 0xa4, 0x36, 0xe2, 0x01, 0xc0,
- 0xe1, 0x23, 0x20, 0x41, 0xf6, 0x00, 0xe0, 0x00,
- 0x46, 0x16, 0xe6, 0x05, 0x07, 0xc6, 0x65, 0x06,
- 0xa5, 0x06, 0x25, 0x07, 0x26, 0x05, 0x80, 0xe2,
- 0x24, 0xe4, 0x37, 0xe2, 0x05, 0x04, 0xe2, 0x1a,
- 0xe4, 0x1d, 0xe6, 0x38, 0xff, 0x80, 0x0e, 0xe2,
- 0x00, 0xff, 0x5a, 0xe2, 0x00, 0xe1, 0x00, 0xa2,
- 0x20, 0xa1, 0x20, 0xe2, 0x00, 0xe1, 0x00, 0xe2,
- 0x00, 0xe1, 0x00, 0xa2, 0x20, 0xa1, 0x20, 0xe2,
- 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x3f, 0xc2, 0xe1, 0x00, 0xe2, 0x06, 0x20, 0xe2,
- 0x00, 0xe3, 0x00, 0xe2, 0x00, 0xe3, 0x00, 0xe2,
- 0x00, 0xe3, 0x00, 0x82, 0x00, 0x22, 0x61, 0x03,
- 0x0e, 0x02, 0x4e, 0x42, 0x00, 0x22, 0x61, 0x03,
- 0x4e, 0x62, 0x20, 0x22, 0x61, 0x00, 0x4e, 0xe2,
- 0x00, 0x81, 0x4e, 0x20, 0x42, 0x00, 0x22, 0x61,
- 0x03, 0x2e, 0x00, 0xf7, 0x03, 0x9b, 0xb1, 0x36,
- 0x14, 0x15, 0x12, 0x34, 0x15, 0x12, 0x14, 0xf6,
- 0x00, 0x18, 0x19, 0x9b, 0x17, 0xf6, 0x01, 0x14,
- 0x15, 0x76, 0x30, 0x56, 0x0c, 0x12, 0x13, 0xf6,
- 0x03, 0x0c, 0x16, 0x10, 0xf6, 0x02, 0x17, 0x9b,
- 0x00, 0xfb, 0x02, 0x0b, 0x04, 0x20, 0xab, 0x4c,
- 0x12, 0x13, 0x04, 0xeb, 0x02, 0x4c, 0x12, 0x13,
- 0x00, 0xe4, 0x05, 0x40, 0xed, 0x19, 0xe0, 0x07,
- 0xe6, 0x05, 0x68, 0x06, 0x48, 0xe6, 0x04, 0xe0,
- 0x07, 0x2f, 0x01, 0x6f, 0x01, 0x2f, 0x02, 0x41,
- 0x22, 0x41, 0x02, 0x0f, 0x01, 0x2f, 0x0c, 0x81,
- 0xaf, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x61,
- 0x0f, 0x02, 0x61, 0x02, 0x65, 0x02, 0x2f, 0x22,
- 0x21, 0x8c, 0x3f, 0x42, 0x0f, 0x0c, 0x2f, 0x02,
- 0x0f, 0xeb, 0x08, 0xea, 0x1b, 0x3f, 0x6a, 0x0b,
- 0x2f, 0x60, 0x8c, 0x8f, 0x2c, 0x6f, 0x0c, 0x2f,
- 0x0c, 0x2f, 0x0c, 0xcf, 0x0c, 0xef, 0x17, 0x2c,
- 0x2f, 0x0c, 0x0f, 0x0c, 0xef, 0x17, 0xec, 0x80,
- 0x84, 0xef, 0x00, 0x12, 0x13, 0x12, 0x13, 0xef,
- 0x0c, 0x2c, 0xcf, 0x12, 0x13, 0xef, 0x49, 0x0c,
- 0xef, 0x16, 0xec, 0x11, 0xef, 0x20, 0xac, 0xef,
- 0x3d, 0xe0, 0x11, 0xef, 0x03, 0xe0, 0x0d, 0xeb,
- 0x34, 0xef, 0x46, 0xeb, 0x0e, 0xef, 0x80, 0x2f,
- 0x0c, 0xef, 0x01, 0x0c, 0xef, 0x2e, 0xec, 0x00,
- 0xef, 0x67, 0x0c, 0xef, 0x80, 0x70, 0x12, 0x13,
- 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
- 0x12, 0x13, 0x12, 0x13, 0xeb, 0x16, 0xef, 0x24,
- 0x8c, 0x12, 0x13, 0xec, 0x17, 0x12, 0x13, 0x12,
- 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0xec,
- 0x08, 0xef, 0x80, 0x78, 0xec, 0x7b, 0x12, 0x13,
+ 0x25, 0x07, 0xe0, 0x04, 0x26, 0x27, 0xe5, 0x01,
+ 0x00, 0x45, 0x00, 0xe5, 0x21, 0x26, 0x05, 0x47,
+ 0x66, 0x00, 0x47, 0x00, 0x47, 0x06, 0x05, 0x0f,
+ 0x60, 0x45, 0x07, 0xcb, 0x45, 0x26, 0x20, 0xe9,
+ 0x02, 0xeb, 0x01, 0x0f, 0xa5, 0x00, 0x06, 0x27,
+ 0x00, 0xe5, 0x0a, 0x40, 0xe5, 0x10, 0x00, 0xe5,
+ 0x01, 0x00, 0x05, 0x20, 0xc5, 0x40, 0x06, 0x60,
+ 0x47, 0x46, 0x00, 0x06, 0x00, 0xe7, 0x00, 0xa0,
+ 0xe9, 0x02, 0x20, 0x27, 0x16, 0xe0, 0x04, 0xe5,
+ 0x28, 0x06, 0x25, 0xc6, 0x60, 0x0d, 0xa5, 0x04,
+ 0xe6, 0x00, 0x16, 0xe9, 0x02, 0x36, 0xe0, 0x1d,
+ 0x25, 0x00, 0x05, 0x00, 0x85, 0x00, 0xe5, 0x10,
+ 0x00, 0x05, 0x00, 0xe5, 0x02, 0x06, 0x25, 0xe6,
+ 0x01, 0x05, 0x20, 0x85, 0x00, 0x04, 0x00, 0xc6,
+ 0x00, 0xe9, 0x02, 0x20, 0x65, 0xe0, 0x18, 0x05,
+ 0x4f, 0xf6, 0x07, 0x0f, 0x16, 0x4f, 0x26, 0xaf,
+ 0xe9, 0x02, 0xeb, 0x02, 0x0f, 0x06, 0x0f, 0x06,
+ 0x0f, 0x06, 0x12, 0x13, 0x12, 0x13, 0x27, 0xe5,
+ 0x00, 0x00, 0xe5, 0x1c, 0x60, 0xe6, 0x06, 0x07,
+ 0x86, 0x16, 0x26, 0x85, 0xe6, 0x03, 0x00, 0xe6,
+ 0x1c, 0x00, 0xef, 0x00, 0x06, 0xaf, 0x00, 0x2f,
+ 0x96, 0x6f, 0x36, 0xe0, 0x1d, 0xe5, 0x23, 0x27,
+ 0x66, 0x07, 0xa6, 0x07, 0x26, 0x27, 0x26, 0x05,
+ 0xe9, 0x02, 0xb6, 0xa5, 0x27, 0x26, 0x65, 0x46,
+ 0x05, 0x47, 0x25, 0xc7, 0x45, 0x66, 0xe5, 0x05,
+ 0x06, 0x27, 0x26, 0xa7, 0x06, 0x05, 0x07, 0xe9,
+ 0x02, 0x47, 0x06, 0x2f, 0xe1, 0x1e, 0x00, 0x01,
+ 0x80, 0x01, 0x20, 0xe2, 0x23, 0x16, 0x04, 0x42,
+ 0xe5, 0x80, 0xc1, 0x00, 0x65, 0x20, 0xc5, 0x00,
+ 0x05, 0x00, 0x65, 0x20, 0xe5, 0x21, 0x00, 0x65,
+ 0x20, 0xe5, 0x19, 0x00, 0x65, 0x20, 0xc5, 0x00,
+ 0x05, 0x00, 0x65, 0x20, 0xe5, 0x07, 0x00, 0xe5,
+ 0x31, 0x00, 0x65, 0x20, 0xe5, 0x3b, 0x20, 0x46,
+ 0xf6, 0x01, 0xeb, 0x0c, 0x40, 0xe5, 0x08, 0xef,
+ 0x02, 0xa0, 0xe1, 0x4e, 0x20, 0xa2, 0x20, 0x11,
+ 0xe5, 0x81, 0xe4, 0x0f, 0x16, 0xe5, 0x09, 0x17,
+ 0xe5, 0x12, 0x12, 0x13, 0x40, 0xe5, 0x43, 0x56,
+ 0x4a, 0xe5, 0x00, 0xc0, 0xe5, 0x0a, 0x46, 0x07,
+ 0xe0, 0x01, 0xe5, 0x0b, 0x26, 0x07, 0x36, 0xe0,
+ 0x01, 0xe5, 0x0a, 0x26, 0xe0, 0x04, 0xe5, 0x05,
+ 0x00, 0x45, 0x00, 0x26, 0xe0, 0x04, 0xe5, 0x2c,
+ 0x26, 0x07, 0xc6, 0xe7, 0x00, 0x06, 0x27, 0xe6,
+ 0x03, 0x56, 0x04, 0x56, 0x0d, 0x05, 0x06, 0x20,
+ 0xe9, 0x02, 0xa0, 0xeb, 0x02, 0xa0, 0xb6, 0x11,
+ 0x76, 0x46, 0x1b, 0x06, 0xe9, 0x02, 0xa0, 0xe5,
+ 0x1b, 0x04, 0xe5, 0x2d, 0xc0, 0x85, 0x26, 0xe5,
+ 0x1a, 0x06, 0x05, 0x80, 0xe5, 0x3e, 0xe0, 0x02,
+ 0xe5, 0x17, 0x00, 0x46, 0x67, 0x26, 0x47, 0x60,
+ 0x27, 0x06, 0xa7, 0x46, 0x60, 0x0f, 0x40, 0x36,
+ 0xe9, 0x02, 0xe5, 0x16, 0x20, 0x85, 0xe0, 0x03,
+ 0xe5, 0x24, 0x60, 0xe5, 0x12, 0xa0, 0xe9, 0x02,
+ 0x0b, 0x40, 0xef, 0x1a, 0xe5, 0x0f, 0x26, 0x27,
+ 0x06, 0x20, 0x36, 0xe5, 0x2d, 0x07, 0x06, 0x07,
+ 0xc6, 0x00, 0x06, 0x07, 0x06, 0x27, 0xe6, 0x00,
+ 0xa7, 0xe6, 0x02, 0x20, 0x06, 0xe9, 0x02, 0xa0,
+ 0xe9, 0x02, 0xa0, 0xd6, 0x04, 0xb6, 0x20, 0xe6,
+ 0x06, 0x08, 0xe6, 0x08, 0xe0, 0x29, 0x66, 0x07,
+ 0xe5, 0x27, 0x06, 0x07, 0x86, 0x07, 0x06, 0x87,
+ 0x06, 0x27, 0xe5, 0x00, 0x40, 0xe9, 0x02, 0xd6,
+ 0xef, 0x02, 0xe6, 0x01, 0xef, 0x01, 0x36, 0x00,
+ 0x26, 0x07, 0xe5, 0x16, 0x07, 0x66, 0x27, 0x26,
+ 0x07, 0x46, 0x25, 0xe9, 0x02, 0xe5, 0x24, 0x06,
+ 0x07, 0x26, 0x47, 0x06, 0x07, 0x46, 0x27, 0xe0,
+ 0x00, 0x76, 0xe5, 0x1c, 0xe7, 0x00, 0xe6, 0x00,
+ 0x27, 0x26, 0x40, 0x96, 0xe9, 0x02, 0x40, 0x45,
+ 0xe9, 0x02, 0xe5, 0x16, 0xa4, 0x36, 0xe2, 0x01,
+ 0xc0, 0xe1, 0x23, 0x20, 0x41, 0xf6, 0x00, 0xe0,
+ 0x00, 0x46, 0x16, 0xe6, 0x05, 0x07, 0xc6, 0x65,
+ 0x06, 0xa5, 0x06, 0x25, 0x07, 0x26, 0x05, 0x80,
+ 0xe2, 0x24, 0xe4, 0x37, 0xe2, 0x05, 0x04, 0xe2,
+ 0x1a, 0xe4, 0x1d, 0xe6, 0x38, 0xff, 0x80, 0x0e,
+ 0xe2, 0x00, 0xff, 0x5a, 0xe2, 0x00, 0xe1, 0x00,
+ 0xa2, 0x20, 0xa1, 0x20, 0xe2, 0x00, 0xe1, 0x00,
+ 0xe2, 0x00, 0xe1, 0x00, 0xa2, 0x20, 0xa1, 0x20,
+ 0xe2, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+ 0x00, 0x3f, 0xc2, 0xe1, 0x00, 0xe2, 0x06, 0x20,
+ 0xe2, 0x00, 0xe3, 0x00, 0xe2, 0x00, 0xe3, 0x00,
+ 0xe2, 0x00, 0xe3, 0x00, 0x82, 0x00, 0x22, 0x61,
+ 0x03, 0x0e, 0x02, 0x4e, 0x42, 0x00, 0x22, 0x61,
+ 0x03, 0x4e, 0x62, 0x20, 0x22, 0x61, 0x00, 0x4e,
+ 0xe2, 0x00, 0x81, 0x4e, 0x20, 0x42, 0x00, 0x22,
+ 0x61, 0x03, 0x2e, 0x00, 0xf7, 0x03, 0x9b, 0xb1,
+ 0x36, 0x14, 0x15, 0x12, 0x34, 0x15, 0x12, 0x14,
+ 0xf6, 0x00, 0x18, 0x19, 0x9b, 0x17, 0xf6, 0x01,
+ 0x14, 0x15, 0x76, 0x30, 0x56, 0x0c, 0x12, 0x13,
+ 0xf6, 0x03, 0x0c, 0x16, 0x10, 0xf6, 0x02, 0x17,
+ 0x9b, 0x00, 0xfb, 0x02, 0x0b, 0x04, 0x20, 0xab,
+ 0x4c, 0x12, 0x13, 0x04, 0xeb, 0x02, 0x4c, 0x12,
+ 0x13, 0x00, 0xe4, 0x05, 0x40, 0xed, 0x19, 0xe0,
+ 0x07, 0xe6, 0x05, 0x68, 0x06, 0x48, 0xe6, 0x04,
+ 0xe0, 0x07, 0x2f, 0x01, 0x6f, 0x01, 0x2f, 0x02,
+ 0x41, 0x22, 0x41, 0x02, 0x0f, 0x01, 0x2f, 0x0c,
+ 0x81, 0xaf, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f,
+ 0x61, 0x0f, 0x02, 0x61, 0x02, 0x65, 0x02, 0x2f,
+ 0x22, 0x21, 0x8c, 0x3f, 0x42, 0x0f, 0x0c, 0x2f,
+ 0x02, 0x0f, 0xeb, 0x08, 0xea, 0x1b, 0x3f, 0x6a,
+ 0x0b, 0x2f, 0x60, 0x8c, 0x8f, 0x2c, 0x6f, 0x0c,
+ 0x2f, 0x0c, 0x2f, 0x0c, 0xcf, 0x0c, 0xef, 0x17,
+ 0x2c, 0x2f, 0x0c, 0x0f, 0x0c, 0xef, 0x17, 0xec,
+ 0x80, 0x84, 0xef, 0x00, 0x12, 0x13, 0x12, 0x13,
+ 0xef, 0x0c, 0x2c, 0xcf, 0x12, 0x13, 0xef, 0x49,
+ 0x0c, 0xef, 0x16, 0xec, 0x11, 0xef, 0x20, 0xac,
+ 0xef, 0x3d, 0xe0, 0x11, 0xef, 0x03, 0xe0, 0x0d,
+ 0xeb, 0x34, 0xef, 0x46, 0xeb, 0x0e, 0xef, 0x80,
+ 0x2f, 0x0c, 0xef, 0x01, 0x0c, 0xef, 0x2e, 0xec,
+ 0x00, 0xef, 0x67, 0x0c, 0xef, 0x80, 0x70, 0x12,
+ 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12,
+ 0x13, 0x12, 0x13, 0x12, 0x13, 0xeb, 0x16, 0xef,
+ 0x24, 0x8c, 0x12, 0x13, 0xec, 0x17, 0x12, 0x13,
0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
- 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
- 0x12, 0x13, 0x12, 0x13, 0xec, 0x37, 0x12, 0x13,
- 0x12, 0x13, 0xec, 0x18, 0x12, 0x13, 0xec, 0x80,
- 0x7a, 0xef, 0x28, 0xec, 0x0d, 0x2f, 0xac, 0xef,
- 0x1f, 0x20, 0xef, 0x18, 0x00, 0xef, 0x61, 0xe1,
- 0x28, 0xe2, 0x28, 0x5f, 0x21, 0x22, 0xdf, 0x41,
- 0x02, 0x3f, 0x02, 0x3f, 0x82, 0x24, 0x41, 0x02,
- 0xff, 0x5a, 0x02, 0xaf, 0x7f, 0x46, 0x3f, 0x80,
- 0x76, 0x0b, 0x36, 0xe2, 0x1e, 0x00, 0x02, 0x80,
- 0x02, 0x20, 0xe5, 0x30, 0xc0, 0x04, 0x16, 0xe0,
- 0x06, 0x06, 0xe5, 0x0f, 0xe0, 0x01, 0xc5, 0x00,
- 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00,
- 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xe6, 0x18,
- 0x36, 0x14, 0x15, 0x14, 0x15, 0x56, 0x14, 0x15,
- 0x16, 0x14, 0x15, 0xf6, 0x01, 0x11, 0x36, 0x11,
- 0x16, 0x14, 0x15, 0x36, 0x14, 0x15, 0x12, 0x13,
- 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x96, 0x04,
- 0xf6, 0x02, 0x31, 0x76, 0x11, 0x16, 0x12, 0xf6,
- 0x05, 0x2f, 0x56, 0x12, 0x13, 0x12, 0x13, 0x12,
- 0x13, 0x12, 0x13, 0x11, 0xe0, 0x1a, 0xef, 0x12,
- 0x00, 0xef, 0x51, 0xe0, 0x04, 0xef, 0x80, 0x4e,
- 0xe0, 0x12, 0xef, 0x04, 0x60, 0x17, 0x56, 0x0f,
- 0x04, 0x05, 0x0a, 0x12, 0x13, 0x12, 0x13, 0x12,
- 0x13, 0x12, 0x13, 0x12, 0x13, 0x2f, 0x12, 0x13,
- 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x11, 0x12,
- 0x33, 0x0f, 0xea, 0x01, 0x66, 0x27, 0x11, 0x84,
- 0x2f, 0x4a, 0x04, 0x05, 0x16, 0x2f, 0x00, 0xe5,
- 0x4e, 0x20, 0x26, 0x2e, 0x24, 0x05, 0x11, 0xe5,
- 0x52, 0x16, 0x44, 0x05, 0x80, 0xe5, 0x23, 0x00,
- 0xe5, 0x56, 0x00, 0x2f, 0x6b, 0xef, 0x02, 0xe5,
- 0x18, 0xef, 0x1c, 0xe0, 0x04, 0xe5, 0x08, 0xef,
- 0x17, 0x00, 0xeb, 0x02, 0xef, 0x16, 0xeb, 0x00,
- 0x0f, 0xeb, 0x07, 0xef, 0x18, 0xeb, 0x02, 0xef,
- 0x1f, 0xeb, 0x07, 0xef, 0x80, 0xb8, 0xe5, 0x99,
- 0x38, 0xef, 0x38, 0xe5, 0xc0, 0x11, 0x8d, 0x04,
- 0xe5, 0x83, 0xef, 0x40, 0xef, 0x2f, 0xe0, 0x01,
- 0xe5, 0x20, 0xa4, 0x36, 0xe5, 0x80, 0x84, 0x04,
- 0x56, 0xe5, 0x08, 0xe9, 0x02, 0x25, 0xe0, 0x0c,
- 0xff, 0x26, 0x05, 0x06, 0x48, 0x16, 0xe6, 0x02,
- 0x16, 0x04, 0xff, 0x14, 0x24, 0x26, 0xe5, 0x3e,
- 0xea, 0x02, 0x26, 0xb6, 0xe0, 0x00, 0xee, 0x0f,
- 0xe4, 0x01, 0x2e, 0xff, 0x06, 0x22, 0xff, 0x36,
- 0x04, 0xe2, 0x00, 0x9f, 0xff, 0x02, 0x04, 0x2e,
- 0x7f, 0x05, 0x7f, 0x22, 0xff, 0x0d, 0x61, 0x02,
- 0x81, 0x02, 0xff, 0x07, 0x41, 0x02, 0x3f, 0x80,
- 0x3f, 0x00, 0x02, 0x00, 0x02, 0x7f, 0xe0, 0x10,
- 0x44, 0x3f, 0x05, 0x24, 0x02, 0xc5, 0x06, 0x45,
- 0x06, 0x65, 0x06, 0xe5, 0x0f, 0x27, 0x26, 0x07,
- 0x6f, 0x06, 0x40, 0xab, 0x2f, 0x0d, 0x0f, 0xa0,
- 0xe5, 0x2c, 0x76, 0xe0, 0x00, 0x27, 0xe5, 0x2a,
- 0xe7, 0x08, 0x26, 0xe0, 0x00, 0x36, 0xe9, 0x02,
- 0xa0, 0xe6, 0x0a, 0xa5, 0x56, 0x05, 0x16, 0x25,
- 0x06, 0xe9, 0x02, 0xe5, 0x14, 0xe6, 0x00, 0x36,
- 0xe5, 0x0f, 0xe6, 0x03, 0x27, 0xe0, 0x03, 0x16,
- 0xe5, 0x15, 0x40, 0x46, 0x07, 0xe5, 0x27, 0x06,
- 0x27, 0x66, 0x27, 0x26, 0x47, 0xf6, 0x05, 0x00,
- 0x04, 0xe9, 0x02, 0x60, 0x36, 0x85, 0x06, 0x04,
- 0xe5, 0x01, 0xe9, 0x02, 0x85, 0x00, 0xe5, 0x21,
- 0xa6, 0x27, 0x26, 0x27, 0x26, 0xe0, 0x01, 0x45,
- 0x06, 0xe5, 0x00, 0x06, 0x07, 0x20, 0xe9, 0x02,
- 0x20, 0x76, 0xe5, 0x08, 0x04, 0xa5, 0x4f, 0x05,
- 0x07, 0x06, 0x07, 0xe5, 0x2a, 0x06, 0x05, 0x46,
- 0x25, 0x26, 0x85, 0x26, 0x05, 0x06, 0x05, 0xe0,
- 0x10, 0x25, 0x04, 0x36, 0xe5, 0x03, 0x07, 0x26,
- 0x27, 0x36, 0x05, 0x24, 0x07, 0x06, 0xe0, 0x02,
- 0xa5, 0x20, 0xa5, 0x20, 0xa5, 0xe0, 0x01, 0xc5,
- 0x00, 0xc5, 0x00, 0xe2, 0x23, 0x0e, 0x64, 0xe2,
- 0x01, 0x04, 0x2e, 0x60, 0xe2, 0x48, 0xe5, 0x1b,
- 0x27, 0x06, 0x27, 0x06, 0x27, 0x16, 0x07, 0x06,
- 0x20, 0xe9, 0x02, 0xa0, 0xe5, 0xab, 0x1c, 0xe0,
- 0x04, 0xe5, 0x0f, 0x60, 0xe5, 0x29, 0x60, 0xfc,
- 0x87, 0x78, 0xfd, 0x98, 0x78, 0xe5, 0x80, 0xe6,
- 0x20, 0xe5, 0x62, 0xe0, 0x1e, 0xc2, 0xe0, 0x04,
- 0x82, 0x80, 0x05, 0x06, 0xe5, 0x02, 0x0c, 0xe5,
- 0x05, 0x00, 0x85, 0x00, 0x05, 0x00, 0x25, 0x00,
- 0x25, 0x00, 0xe5, 0x64, 0xee, 0x09, 0xe0, 0x08,
- 0xe5, 0x80, 0xe3, 0x13, 0x12, 0xef, 0x08, 0xe5,
- 0x38, 0x20, 0xe5, 0x2e, 0xc0, 0x0f, 0xe0, 0x18,
- 0xe5, 0x04, 0x0d, 0x4f, 0xe6, 0x08, 0xd6, 0x12,
- 0x13, 0x16, 0xa0, 0xe6, 0x08, 0x16, 0x31, 0x30,
- 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
- 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
- 0x36, 0x12, 0x13, 0x76, 0x50, 0x56, 0x00, 0x76,
- 0x11, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x56,
- 0x0c, 0x11, 0x4c, 0x00, 0x16, 0x0d, 0x36, 0x60,
- 0x85, 0x00, 0xe5, 0x7f, 0x20, 0x1b, 0x00, 0x56,
- 0x0d, 0x56, 0x12, 0x13, 0x16, 0x0c, 0x16, 0x11,
- 0x36, 0xe9, 0x02, 0x36, 0x4c, 0x36, 0xe1, 0x12,
- 0x12, 0x16, 0x13, 0x0e, 0x10, 0x0e, 0xe2, 0x12,
- 0x12, 0x0c, 0x13, 0x0c, 0x12, 0x13, 0x16, 0x12,
- 0x13, 0x36, 0xe5, 0x02, 0x04, 0xe5, 0x25, 0x24,
- 0xe5, 0x17, 0x40, 0xa5, 0x20, 0xa5, 0x20, 0xa5,
- 0x20, 0x45, 0x40, 0x2d, 0x0c, 0x0e, 0x0f, 0x2d,
- 0x00, 0x0f, 0x6c, 0x2f, 0xe0, 0x02, 0x5b, 0x2f,
- 0x20, 0xe5, 0x04, 0x00, 0xe5, 0x12, 0x00, 0xe5,
- 0x0b, 0x00, 0x25, 0x00, 0xe5, 0x07, 0x20, 0xe5,
- 0x06, 0xe0, 0x1a, 0xe5, 0x73, 0x80, 0x56, 0x60,
- 0xeb, 0x25, 0x40, 0xef, 0x01, 0xea, 0x2d, 0x6b,
- 0xef, 0x09, 0x2b, 0x4f, 0x00, 0xef, 0x05, 0x40,
- 0x0f, 0xe0, 0x27, 0xef, 0x25, 0x06, 0xe0, 0x7a,
- 0xe5, 0x15, 0x40, 0xe5, 0x29, 0xe0, 0x07, 0x06,
- 0xeb, 0x13, 0x60, 0xe5, 0x18, 0x6b, 0xe0, 0x01,
- 0xe5, 0x0c, 0x0a, 0xe5, 0x00, 0x0a, 0x80, 0xe5,
- 0x1e, 0x86, 0x80, 0xe5, 0x16, 0x00, 0x16, 0xe5,
- 0x1c, 0x60, 0xe5, 0x00, 0x16, 0x8a, 0xe0, 0x22,
- 0xe1, 0x20, 0xe2, 0x20, 0xe5, 0x46, 0x20, 0xe9,
- 0x02, 0xa0, 0xe1, 0x1c, 0x60, 0xe2, 0x1c, 0x60,
- 0xe5, 0x20, 0xe0, 0x00, 0xe5, 0x2c, 0xe0, 0x03,
- 0x16, 0xe1, 0x03, 0x00, 0xe1, 0x07, 0x00, 0xc1,
- 0x00, 0x21, 0x00, 0xe2, 0x03, 0x00, 0xe2, 0x07,
- 0x00, 0xc2, 0x00, 0x22, 0xe0, 0x3b, 0xe5, 0x80,
- 0xaf, 0xe0, 0x01, 0xe5, 0x0e, 0xe0, 0x02, 0xe5,
- 0x00, 0xe0, 0x10, 0xa4, 0x00, 0xe4, 0x22, 0x00,
- 0xe4, 0x01, 0xe0, 0x3d, 0xa5, 0x20, 0x05, 0x00,
- 0xe5, 0x24, 0x00, 0x25, 0x40, 0x05, 0x20, 0xe5,
- 0x0f, 0x00, 0x16, 0xeb, 0x00, 0xe5, 0x0f, 0x2f,
- 0xcb, 0xe5, 0x17, 0xe0, 0x00, 0xeb, 0x01, 0xe0,
- 0x28, 0xe5, 0x0b, 0x00, 0x25, 0x80, 0x8b, 0xe5,
- 0x0e, 0xab, 0x40, 0x16, 0xe5, 0x12, 0x80, 0x16,
- 0xe0, 0x38, 0xe5, 0x30, 0x60, 0x2b, 0x25, 0xeb,
- 0x08, 0x20, 0xeb, 0x26, 0x05, 0x46, 0x00, 0x26,
- 0x80, 0x66, 0x65, 0x00, 0x45, 0x00, 0xe5, 0x15,
- 0x20, 0x46, 0x60, 0x06, 0xeb, 0x01, 0xc0, 0xf6,
- 0x01, 0xc0, 0xe5, 0x15, 0x2b, 0x16, 0xe5, 0x15,
- 0x4b, 0xe0, 0x18, 0xe5, 0x00, 0x0f, 0xe5, 0x14,
- 0x26, 0x60, 0x8b, 0xd6, 0xe0, 0x01, 0xe5, 0x2e,
- 0x40, 0xd6, 0xe5, 0x0e, 0x20, 0xeb, 0x00, 0xe5,
- 0x0b, 0x80, 0xeb, 0x00, 0xe5, 0x0a, 0xc0, 0x76,
- 0xe0, 0x04, 0xcb, 0xe0, 0x48, 0xe5, 0x41, 0xe0,
- 0x2f, 0xe1, 0x2b, 0xe0, 0x05, 0xe2, 0x2b, 0xc0,
- 0xab, 0xe5, 0x1c, 0x66, 0xe0, 0x00, 0xe9, 0x02,
- 0xe0, 0x80, 0x9e, 0xeb, 0x17, 0x00, 0xe5, 0x22,
- 0x00, 0x26, 0x11, 0x20, 0x25, 0xe0, 0x46, 0xe5,
- 0x15, 0xeb, 0x02, 0x05, 0xe0, 0x00, 0xe5, 0x0e,
- 0xe6, 0x03, 0x6b, 0x96, 0xe0, 0x0e, 0xe5, 0x0a,
- 0x66, 0x76, 0xe0, 0x1e, 0xe5, 0x0d, 0xcb, 0xe0,
- 0x0c, 0xe5, 0x0f, 0xe0, 0x01, 0x07, 0x06, 0x07,
- 0xe5, 0x2d, 0xe6, 0x07, 0xd6, 0x60, 0xeb, 0x0c,
- 0xe9, 0x02, 0x06, 0x25, 0x26, 0x05, 0xe0, 0x01,
- 0x46, 0x07, 0xe5, 0x25, 0x47, 0x66, 0x27, 0x26,
- 0x36, 0x1b, 0x76, 0x06, 0xe0, 0x02, 0x1b, 0x20,
- 0xe5, 0x11, 0xc0, 0xe9, 0x02, 0xa0, 0x46, 0xe5,
- 0x1c, 0x86, 0x07, 0xe6, 0x00, 0x00, 0xe9, 0x02,
- 0x76, 0x05, 0x27, 0x05, 0xe0, 0x00, 0xe5, 0x1b,
- 0x06, 0x36, 0x05, 0xe0, 0x01, 0x26, 0x07, 0xe5,
- 0x28, 0x47, 0xe6, 0x01, 0x27, 0x65, 0x76, 0x66,
- 0x16, 0x07, 0x06, 0xe9, 0x02, 0x05, 0x16, 0x05,
- 0x56, 0x00, 0xeb, 0x0c, 0xe0, 0x03, 0xe5, 0x0a,
- 0x00, 0xe5, 0x11, 0x47, 0x46, 0x27, 0x06, 0x07,
- 0x26, 0xb6, 0x06, 0xe0, 0x39, 0xc5, 0x00, 0x05,
- 0x00, 0x65, 0x00, 0xe5, 0x07, 0x00, 0xe5, 0x02,
- 0x16, 0xa0, 0xe5, 0x27, 0x06, 0x47, 0xe6, 0x00,
- 0x80, 0xe9, 0x02, 0xa0, 0x26, 0x27, 0x00, 0xe5,
- 0x00, 0x20, 0x25, 0x20, 0xe5, 0x0e, 0x00, 0xc5,
- 0x00, 0x25, 0x00, 0x85, 0x00, 0x26, 0x05, 0x27,
- 0x06, 0x67, 0x20, 0x27, 0x20, 0x47, 0x20, 0x05,
- 0xa0, 0x07, 0x80, 0x85, 0x27, 0x20, 0xc6, 0x40,
- 0x86, 0xe0, 0x80, 0x03, 0xe5, 0x2d, 0x47, 0xe6,
- 0x00, 0x27, 0x46, 0x07, 0x06, 0x65, 0x96, 0xe9,
- 0x02, 0x36, 0x00, 0x16, 0x06, 0x45, 0xe0, 0x16,
- 0xe5, 0x28, 0x47, 0xa6, 0x07, 0x06, 0x67, 0x26,
- 0x07, 0x26, 0x25, 0x16, 0x05, 0xe0, 0x00, 0xe9,
- 0x02, 0xe0, 0x80, 0x1e, 0xe5, 0x27, 0x47, 0x66,
- 0x20, 0x67, 0x26, 0x07, 0x26, 0xf6, 0x0f, 0x65,
- 0x26, 0xe0, 0x1a, 0xe5, 0x28, 0x47, 0xe6, 0x00,
- 0x27, 0x06, 0x07, 0x26, 0x56, 0x05, 0xe0, 0x03,
- 0xe9, 0x02, 0xa0, 0xf6, 0x05, 0xe0, 0x0b, 0xe5,
- 0x23, 0x06, 0x07, 0x06, 0x27, 0xa6, 0x07, 0x06,
- 0x05, 0x16, 0xa0, 0xe9, 0x02, 0xe0, 0x2e, 0xe5,
- 0x13, 0x20, 0x46, 0x27, 0x66, 0x07, 0x86, 0x60,
- 0xe9, 0x02, 0x2b, 0x56, 0x0f, 0xc5, 0xe0, 0x80,
- 0x31, 0xe5, 0x24, 0x47, 0xe6, 0x01, 0x07, 0x26,
- 0x16, 0xe0, 0x5c, 0xe1, 0x18, 0xe2, 0x18, 0xe9,
- 0x02, 0xeb, 0x01, 0xe0, 0x04, 0xe5, 0x00, 0x20,
- 0x05, 0x20, 0xe5, 0x00, 0x00, 0x25, 0x00, 0xe5,
- 0x10, 0xa7, 0x00, 0x27, 0x20, 0x26, 0x07, 0x06,
- 0x05, 0x07, 0x05, 0x07, 0x06, 0x56, 0xe0, 0x01,
- 0xe9, 0x02, 0xe0, 0x3e, 0xe5, 0x00, 0x20, 0xe5,
- 0x1f, 0x47, 0x66, 0x20, 0x26, 0x67, 0x06, 0x05,
- 0x16, 0x05, 0x07, 0xe0, 0x13, 0x05, 0xe6, 0x02,
- 0xe5, 0x20, 0xa6, 0x07, 0x05, 0x66, 0xf6, 0x00,
- 0x06, 0xe0, 0x00, 0x05, 0xa6, 0x27, 0x46, 0xe5,
- 0x26, 0xe6, 0x05, 0x07, 0x26, 0x56, 0x05, 0x96,
- 0xe0, 0x05, 0xe5, 0x41, 0xe0, 0x80, 0x7f, 0xe5,
- 0x01, 0x00, 0xe5, 0x1d, 0x07, 0xc6, 0x00, 0xa6,
- 0x07, 0x06, 0x05, 0x96, 0xe0, 0x02, 0xe9, 0x02,
- 0xeb, 0x0b, 0x40, 0x36, 0xe5, 0x16, 0x20, 0xe6,
- 0x0e, 0x00, 0x07, 0xc6, 0x07, 0x26, 0x07, 0x26,
- 0xe0, 0x41, 0xc5, 0x00, 0x25, 0x00, 0xe5, 0x1e,
- 0xa6, 0x40, 0x06, 0x00, 0x26, 0x00, 0xc6, 0x05,
- 0x06, 0xe0, 0x00, 0xe9, 0x02, 0xa0, 0xa5, 0x00,
- 0x25, 0x00, 0xe5, 0x18, 0x87, 0x00, 0x26, 0x00,
- 0x27, 0x06, 0x07, 0x06, 0x05, 0xc0, 0xe9, 0x02,
- 0xe0, 0x80, 0xae, 0xe5, 0x0b, 0x26, 0x27, 0x36,
- 0xe0, 0x80, 0x2f, 0x05, 0xe0, 0x07, 0xeb, 0x0d,
- 0xef, 0x00, 0x6d, 0xef, 0x09, 0xe0, 0x05, 0x16,
- 0xe5, 0x83, 0x12, 0xe0, 0x5e, 0xea, 0x67, 0x00,
- 0x96, 0xe0, 0x03, 0xe5, 0x80, 0x3c, 0xe0, 0x89,
- 0xc4, 0xe5, 0x59, 0x36, 0xe0, 0x05, 0xe5, 0x83,
- 0xa7, 0x00, 0xfb, 0x01, 0xe0, 0x8f, 0x3f, 0xe5,
- 0x81, 0xbf, 0xe0, 0xa1, 0x31, 0xe5, 0x81, 0xb1,
- 0xc0, 0xe5, 0x17, 0x00, 0xe9, 0x02, 0x60, 0x36,
- 0xe5, 0x47, 0x00, 0xe9, 0x02, 0xa0, 0xe5, 0x16,
- 0x20, 0x86, 0x16, 0xe0, 0x02, 0xe5, 0x28, 0xc6,
- 0x96, 0x6f, 0x64, 0x16, 0x0f, 0xe0, 0x02, 0xe9,
- 0x02, 0x00, 0xcb, 0x00, 0xe5, 0x0d, 0x80, 0xe5,
- 0x0b, 0xe0, 0x82, 0x28, 0xe1, 0x18, 0xe2, 0x18,
- 0xeb, 0x0f, 0x76, 0xe0, 0x5d, 0xe5, 0x43, 0x60,
- 0x06, 0x05, 0xe7, 0x2f, 0xc0, 0x66, 0xe4, 0x05,
- 0xe0, 0x38, 0x24, 0x16, 0x04, 0x06, 0xe0, 0x03,
- 0x27, 0xe0, 0x06, 0xe5, 0x97, 0x70, 0xe0, 0x00,
- 0xe5, 0x84, 0x4e, 0xe0, 0x22, 0xe5, 0x01, 0xe0,
- 0xa2, 0x5f, 0x64, 0x00, 0xc4, 0x00, 0x24, 0x00,
- 0xe5, 0x80, 0x9b, 0xe0, 0x25, 0x45, 0xe0, 0x09,
- 0x65, 0xe0, 0x00, 0xe5, 0x81, 0x04, 0xe0, 0x88,
- 0x7c, 0xe5, 0x63, 0x80, 0xe5, 0x05, 0x40, 0xe5,
- 0x01, 0xc0, 0xe5, 0x02, 0x20, 0x0f, 0x26, 0x16,
- 0x7b, 0xe0, 0x91, 0xd4, 0xe6, 0x26, 0x20, 0xe6,
- 0x0f, 0xe0, 0x01, 0xef, 0x6c, 0xe0, 0x34, 0xef,
- 0x80, 0x6e, 0xe0, 0x02, 0xef, 0x1f, 0x20, 0xef,
- 0x34, 0x27, 0x46, 0x4f, 0xa7, 0xfb, 0x00, 0xe6,
- 0x00, 0x2f, 0xc6, 0xef, 0x16, 0x66, 0xef, 0x35,
- 0xe0, 0x0d, 0xef, 0x3a, 0x46, 0x0f, 0xe0, 0x80,
- 0x12, 0xeb, 0x0c, 0xe0, 0x04, 0xef, 0x4f, 0xe0,
- 0x01, 0xeb, 0x11, 0xe0, 0x7f, 0xe1, 0x12, 0xe2,
- 0x12, 0xe1, 0x12, 0xc2, 0x00, 0xe2, 0x0a, 0xe1,
- 0x12, 0xe2, 0x12, 0x01, 0x00, 0x21, 0x20, 0x01,
- 0x20, 0x21, 0x20, 0x61, 0x00, 0xe1, 0x00, 0x62,
- 0x00, 0x02, 0x00, 0xc2, 0x00, 0xe2, 0x03, 0xe1,
- 0x12, 0xe2, 0x12, 0x21, 0x00, 0x61, 0x20, 0xe1,
- 0x00, 0x00, 0xc1, 0x00, 0xe2, 0x12, 0x21, 0x00,
- 0x61, 0x00, 0x81, 0x00, 0x01, 0x40, 0xc1, 0x00,
- 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12,
- 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12,
- 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12,
- 0xe2, 0x14, 0x20, 0xe1, 0x11, 0x0c, 0xe2, 0x11,
- 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c,
- 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2,
+ 0xec, 0x08, 0xef, 0x80, 0x78, 0xec, 0x7b, 0x12,
+ 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12,
+ 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12,
+ 0x13, 0x12, 0x13, 0x12, 0x13, 0xec, 0x37, 0x12,
+ 0x13, 0x12, 0x13, 0xec, 0x18, 0x12, 0x13, 0xec,
+ 0x80, 0x7a, 0xef, 0x28, 0xec, 0x0d, 0x2f, 0xac,
+ 0xef, 0x1f, 0x20, 0xef, 0x18, 0x00, 0xef, 0x61,
+ 0xe1, 0x28, 0xe2, 0x28, 0x5f, 0x21, 0x22, 0xdf,
+ 0x41, 0x02, 0x3f, 0x02, 0x3f, 0x82, 0x24, 0x41,
+ 0x02, 0xff, 0x5a, 0x02, 0xaf, 0x7f, 0x46, 0x3f,
+ 0x80, 0x76, 0x0b, 0x36, 0xe2, 0x1e, 0x00, 0x02,
+ 0x80, 0x02, 0x20, 0xe5, 0x30, 0xc0, 0x04, 0x16,
+ 0xe0, 0x06, 0x06, 0xe5, 0x0f, 0xe0, 0x01, 0xc5,
+ 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5,
+ 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xe6,
+ 0x18, 0x36, 0x14, 0x15, 0x14, 0x15, 0x56, 0x14,
+ 0x15, 0x16, 0x14, 0x15, 0xf6, 0x01, 0x11, 0x36,
+ 0x11, 0x16, 0x14, 0x15, 0x36, 0x14, 0x15, 0x12,
+ 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x96,
+ 0x04, 0xf6, 0x02, 0x31, 0x76, 0x11, 0x16, 0x12,
+ 0xf6, 0x05, 0x2f, 0x56, 0x12, 0x13, 0x12, 0x13,
+ 0x12, 0x13, 0x12, 0x13, 0x11, 0xe0, 0x1a, 0xef,
+ 0x12, 0x00, 0xef, 0x51, 0xe0, 0x04, 0xef, 0x80,
+ 0x4e, 0xe0, 0x12, 0xef, 0x04, 0x60, 0x17, 0x56,
+ 0x0f, 0x04, 0x05, 0x0a, 0x12, 0x13, 0x12, 0x13,
+ 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x2f, 0x12,
+ 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x11,
+ 0x12, 0x33, 0x0f, 0xea, 0x01, 0x66, 0x27, 0x11,
+ 0x84, 0x2f, 0x4a, 0x04, 0x05, 0x16, 0x2f, 0x00,
+ 0xe5, 0x4e, 0x20, 0x26, 0x2e, 0x24, 0x05, 0x11,
+ 0xe5, 0x52, 0x16, 0x44, 0x05, 0x80, 0xe5, 0x23,
+ 0x00, 0xe5, 0x56, 0x00, 0x2f, 0x6b, 0xef, 0x02,
+ 0xe5, 0x18, 0xef, 0x1c, 0xe0, 0x04, 0xe5, 0x08,
+ 0xef, 0x17, 0x00, 0xeb, 0x02, 0xef, 0x16, 0xeb,
+ 0x00, 0x0f, 0xeb, 0x07, 0xef, 0x18, 0xeb, 0x02,
+ 0xef, 0x1f, 0xeb, 0x07, 0xef, 0x80, 0xb8, 0xe5,
+ 0x99, 0x38, 0xef, 0x38, 0xe5, 0xc0, 0x11, 0x8d,
+ 0x04, 0xe5, 0x83, 0xef, 0x40, 0xef, 0x2f, 0xe0,
+ 0x01, 0xe5, 0x20, 0xa4, 0x36, 0xe5, 0x80, 0x84,
+ 0x04, 0x56, 0xe5, 0x08, 0xe9, 0x02, 0x25, 0xe0,
+ 0x0c, 0xff, 0x26, 0x05, 0x06, 0x48, 0x16, 0xe6,
+ 0x02, 0x16, 0x04, 0xff, 0x14, 0x24, 0x26, 0xe5,
+ 0x3e, 0xea, 0x02, 0x26, 0xb6, 0xe0, 0x00, 0xee,
+ 0x0f, 0xe4, 0x01, 0x2e, 0xff, 0x06, 0x22, 0xff,
+ 0x36, 0x04, 0xe2, 0x00, 0x9f, 0xff, 0x02, 0x04,
+ 0x2e, 0x7f, 0x05, 0x7f, 0x22, 0xff, 0x0d, 0x61,
+ 0x02, 0x81, 0x02, 0xff, 0x07, 0x41, 0x02, 0x3f,
+ 0x80, 0x3f, 0x00, 0x02, 0x00, 0x02, 0x7f, 0xe0,
+ 0x10, 0x44, 0x3f, 0x05, 0x24, 0x02, 0xc5, 0x06,
+ 0x45, 0x06, 0x65, 0x06, 0xe5, 0x0f, 0x27, 0x26,
+ 0x07, 0x6f, 0x06, 0x40, 0xab, 0x2f, 0x0d, 0x0f,
+ 0xa0, 0xe5, 0x2c, 0x76, 0xe0, 0x00, 0x27, 0xe5,
+ 0x2a, 0xe7, 0x08, 0x26, 0xe0, 0x00, 0x36, 0xe9,
+ 0x02, 0xa0, 0xe6, 0x0a, 0xa5, 0x56, 0x05, 0x16,
+ 0x25, 0x06, 0xe9, 0x02, 0xe5, 0x14, 0xe6, 0x00,
+ 0x36, 0xe5, 0x0f, 0xe6, 0x03, 0x27, 0xe0, 0x03,
+ 0x16, 0xe5, 0x15, 0x40, 0x46, 0x07, 0xe5, 0x27,
+ 0x06, 0x27, 0x66, 0x27, 0x26, 0x47, 0xf6, 0x05,
+ 0x00, 0x04, 0xe9, 0x02, 0x60, 0x36, 0x85, 0x06,
+ 0x04, 0xe5, 0x01, 0xe9, 0x02, 0x85, 0x00, 0xe5,
+ 0x21, 0xa6, 0x27, 0x26, 0x27, 0x26, 0xe0, 0x01,
+ 0x45, 0x06, 0xe5, 0x00, 0x06, 0x07, 0x20, 0xe9,
+ 0x02, 0x20, 0x76, 0xe5, 0x08, 0x04, 0xa5, 0x4f,
+ 0x05, 0x07, 0x06, 0x07, 0xe5, 0x2a, 0x06, 0x05,
+ 0x46, 0x25, 0x26, 0x85, 0x26, 0x05, 0x06, 0x05,
+ 0xe0, 0x10, 0x25, 0x04, 0x36, 0xe5, 0x03, 0x07,
+ 0x26, 0x27, 0x36, 0x05, 0x24, 0x07, 0x06, 0xe0,
+ 0x02, 0xa5, 0x20, 0xa5, 0x20, 0xa5, 0xe0, 0x01,
+ 0xc5, 0x00, 0xc5, 0x00, 0xe2, 0x23, 0x0e, 0x64,
+ 0xe2, 0x01, 0x04, 0x2e, 0x60, 0xe2, 0x48, 0xe5,
+ 0x1b, 0x27, 0x06, 0x27, 0x06, 0x27, 0x16, 0x07,
+ 0x06, 0x20, 0xe9, 0x02, 0xa0, 0xe5, 0xab, 0x1c,
+ 0xe0, 0x04, 0xe5, 0x0f, 0x60, 0xe5, 0x29, 0x60,
+ 0xfc, 0x87, 0x78, 0xfd, 0x98, 0x78, 0xe5, 0x80,
+ 0xe6, 0x20, 0xe5, 0x62, 0xe0, 0x1e, 0xc2, 0xe0,
+ 0x04, 0x82, 0x80, 0x05, 0x06, 0xe5, 0x02, 0x0c,
+ 0xe5, 0x05, 0x00, 0x85, 0x00, 0x05, 0x00, 0x25,
+ 0x00, 0x25, 0x00, 0xe5, 0x64, 0xee, 0x09, 0xe0,
+ 0x08, 0xe5, 0x80, 0xe3, 0x13, 0x12, 0xef, 0x08,
+ 0xe5, 0x38, 0x20, 0xe5, 0x2e, 0xc0, 0x0f, 0xe0,
+ 0x18, 0xe5, 0x04, 0x0d, 0x4f, 0xe6, 0x08, 0xd6,
+ 0x12, 0x13, 0x16, 0xa0, 0xe6, 0x08, 0x16, 0x31,
+ 0x30, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12,
+ 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12,
+ 0x13, 0x36, 0x12, 0x13, 0x76, 0x50, 0x56, 0x00,
+ 0x76, 0x11, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
+ 0x56, 0x0c, 0x11, 0x4c, 0x00, 0x16, 0x0d, 0x36,
+ 0x60, 0x85, 0x00, 0xe5, 0x7f, 0x20, 0x1b, 0x00,
+ 0x56, 0x0d, 0x56, 0x12, 0x13, 0x16, 0x0c, 0x16,
+ 0x11, 0x36, 0xe9, 0x02, 0x36, 0x4c, 0x36, 0xe1,
+ 0x12, 0x12, 0x16, 0x13, 0x0e, 0x10, 0x0e, 0xe2,
+ 0x12, 0x12, 0x0c, 0x13, 0x0c, 0x12, 0x13, 0x16,
+ 0x12, 0x13, 0x36, 0xe5, 0x02, 0x04, 0xe5, 0x25,
+ 0x24, 0xe5, 0x17, 0x40, 0xa5, 0x20, 0xa5, 0x20,
+ 0xa5, 0x20, 0x45, 0x40, 0x2d, 0x0c, 0x0e, 0x0f,
+ 0x2d, 0x00, 0x0f, 0x6c, 0x2f, 0xe0, 0x02, 0x5b,
+ 0x2f, 0x20, 0xe5, 0x04, 0x00, 0xe5, 0x12, 0x00,
+ 0xe5, 0x0b, 0x00, 0x25, 0x00, 0xe5, 0x07, 0x20,
+ 0xe5, 0x06, 0xe0, 0x1a, 0xe5, 0x73, 0x80, 0x56,
+ 0x60, 0xeb, 0x25, 0x40, 0xef, 0x01, 0xea, 0x2d,
+ 0x6b, 0xef, 0x09, 0x2b, 0x4f, 0x00, 0xef, 0x05,
+ 0x40, 0x0f, 0xe0, 0x27, 0xef, 0x25, 0x06, 0xe0,
+ 0x7a, 0xe5, 0x15, 0x40, 0xe5, 0x29, 0xe0, 0x07,
+ 0x06, 0xeb, 0x13, 0x60, 0xe5, 0x18, 0x6b, 0xe0,
+ 0x01, 0xe5, 0x0c, 0x0a, 0xe5, 0x00, 0x0a, 0x80,
+ 0xe5, 0x1e, 0x86, 0x80, 0xe5, 0x16, 0x00, 0x16,
+ 0xe5, 0x1c, 0x60, 0xe5, 0x00, 0x16, 0x8a, 0xe0,
+ 0x22, 0xe1, 0x20, 0xe2, 0x20, 0xe5, 0x46, 0x20,
+ 0xe9, 0x02, 0xa0, 0xe1, 0x1c, 0x60, 0xe2, 0x1c,
+ 0x60, 0xe5, 0x20, 0xe0, 0x00, 0xe5, 0x2c, 0xe0,
+ 0x03, 0x16, 0xe1, 0x03, 0x00, 0xe1, 0x07, 0x00,
+ 0xc1, 0x00, 0x21, 0x00, 0xe2, 0x03, 0x00, 0xe2,
+ 0x07, 0x00, 0xc2, 0x00, 0x22, 0xe0, 0x3b, 0xe5,
+ 0x80, 0xaf, 0xe0, 0x01, 0xe5, 0x0e, 0xe0, 0x02,
+ 0xe5, 0x00, 0xe0, 0x10, 0xa4, 0x00, 0xe4, 0x22,
+ 0x00, 0xe4, 0x01, 0xe0, 0x3d, 0xa5, 0x20, 0x05,
+ 0x00, 0xe5, 0x24, 0x00, 0x25, 0x40, 0x05, 0x20,
+ 0xe5, 0x0f, 0x00, 0x16, 0xeb, 0x00, 0xe5, 0x0f,
+ 0x2f, 0xcb, 0xe5, 0x17, 0xe0, 0x00, 0xeb, 0x01,
+ 0xe0, 0x28, 0xe5, 0x0b, 0x00, 0x25, 0x80, 0x8b,
+ 0xe5, 0x0e, 0xab, 0x40, 0x16, 0xe5, 0x12, 0x80,
+ 0x16, 0xe0, 0x38, 0xe5, 0x30, 0x60, 0x2b, 0x25,
+ 0xeb, 0x08, 0x20, 0xeb, 0x26, 0x05, 0x46, 0x00,
+ 0x26, 0x80, 0x66, 0x65, 0x00, 0x45, 0x00, 0xe5,
+ 0x15, 0x20, 0x46, 0x60, 0x06, 0xeb, 0x01, 0xc0,
+ 0xf6, 0x01, 0xc0, 0xe5, 0x15, 0x2b, 0x16, 0xe5,
+ 0x15, 0x4b, 0xe0, 0x18, 0xe5, 0x00, 0x0f, 0xe5,
+ 0x14, 0x26, 0x60, 0x8b, 0xd6, 0xe0, 0x01, 0xe5,
+ 0x2e, 0x40, 0xd6, 0xe5, 0x0e, 0x20, 0xeb, 0x00,
+ 0xe5, 0x0b, 0x80, 0xeb, 0x00, 0xe5, 0x0a, 0xc0,
+ 0x76, 0xe0, 0x04, 0xcb, 0xe0, 0x48, 0xe5, 0x41,
+ 0xe0, 0x2f, 0xe1, 0x2b, 0xe0, 0x05, 0xe2, 0x2b,
+ 0xc0, 0xab, 0xe5, 0x1c, 0x66, 0xe0, 0x00, 0xe9,
+ 0x02, 0xe0, 0x80, 0x9e, 0xeb, 0x17, 0x00, 0xe5,
+ 0x22, 0x00, 0x26, 0x11, 0x20, 0x25, 0xe0, 0x43,
+ 0x46, 0xe5, 0x15, 0xeb, 0x02, 0x05, 0xe0, 0x00,
+ 0xe5, 0x0e, 0xe6, 0x03, 0x6b, 0x96, 0xe0, 0x0e,
+ 0xe5, 0x0a, 0x66, 0x76, 0xe0, 0x1e, 0xe5, 0x0d,
+ 0xcb, 0xe0, 0x0c, 0xe5, 0x0f, 0xe0, 0x01, 0x07,
+ 0x06, 0x07, 0xe5, 0x2d, 0xe6, 0x07, 0xd6, 0x60,
+ 0xeb, 0x0c, 0xe9, 0x02, 0x06, 0x25, 0x26, 0x05,
+ 0xe0, 0x01, 0x46, 0x07, 0xe5, 0x25, 0x47, 0x66,
+ 0x27, 0x26, 0x36, 0x1b, 0x76, 0x06, 0xe0, 0x02,
+ 0x1b, 0x20, 0xe5, 0x11, 0xc0, 0xe9, 0x02, 0xa0,
+ 0x46, 0xe5, 0x1c, 0x86, 0x07, 0xe6, 0x00, 0x00,
+ 0xe9, 0x02, 0x76, 0x05, 0x27, 0x05, 0xe0, 0x00,
+ 0xe5, 0x1b, 0x06, 0x36, 0x05, 0xe0, 0x01, 0x26,
+ 0x07, 0xe5, 0x28, 0x47, 0xe6, 0x01, 0x27, 0x65,
+ 0x76, 0x66, 0x16, 0x07, 0x06, 0xe9, 0x02, 0x05,
+ 0x16, 0x05, 0x56, 0x00, 0xeb, 0x0c, 0xe0, 0x03,
+ 0xe5, 0x0a, 0x00, 0xe5, 0x11, 0x47, 0x46, 0x27,
+ 0x06, 0x07, 0x26, 0xb6, 0x06, 0x25, 0x06, 0xe0,
+ 0x36, 0xc5, 0x00, 0x05, 0x00, 0x65, 0x00, 0xe5,
+ 0x07, 0x00, 0xe5, 0x02, 0x16, 0xa0, 0xe5, 0x27,
+ 0x06, 0x47, 0xe6, 0x00, 0x80, 0xe9, 0x02, 0xa0,
+ 0x26, 0x27, 0x00, 0xe5, 0x00, 0x20, 0x25, 0x20,
+ 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00, 0x85,
+ 0x00, 0x26, 0x05, 0x27, 0x06, 0x67, 0x20, 0x27,
+ 0x20, 0x47, 0x20, 0x05, 0xa0, 0x07, 0x80, 0x85,
+ 0x27, 0x20, 0xc6, 0x40, 0x86, 0xe0, 0x80, 0x03,
+ 0xe5, 0x2d, 0x47, 0xe6, 0x00, 0x27, 0x46, 0x07,
+ 0x06, 0x65, 0x96, 0xe9, 0x02, 0x36, 0x00, 0x16,
+ 0x06, 0x45, 0xe0, 0x16, 0xe5, 0x28, 0x47, 0xa6,
+ 0x07, 0x06, 0x67, 0x26, 0x07, 0x26, 0x25, 0x16,
+ 0x05, 0xe0, 0x00, 0xe9, 0x02, 0xe0, 0x80, 0x1e,
+ 0xe5, 0x27, 0x47, 0x66, 0x20, 0x67, 0x26, 0x07,
+ 0x26, 0xf6, 0x0f, 0x65, 0x26, 0xe0, 0x1a, 0xe5,
+ 0x28, 0x47, 0xe6, 0x00, 0x27, 0x06, 0x07, 0x26,
+ 0x56, 0x05, 0xe0, 0x03, 0xe9, 0x02, 0xa0, 0xf6,
+ 0x05, 0xe0, 0x0b, 0xe5, 0x23, 0x06, 0x07, 0x06,
+ 0x27, 0xa6, 0x07, 0x06, 0x05, 0x16, 0xa0, 0xe9,
+ 0x02, 0xe0, 0x2e, 0xe5, 0x13, 0x20, 0x46, 0x27,
+ 0x66, 0x07, 0x86, 0x60, 0xe9, 0x02, 0x2b, 0x56,
+ 0x0f, 0xc5, 0xe0, 0x80, 0x31, 0xe5, 0x24, 0x47,
+ 0xe6, 0x01, 0x07, 0x26, 0x16, 0xe0, 0x5c, 0xe1,
+ 0x18, 0xe2, 0x18, 0xe9, 0x02, 0xeb, 0x01, 0xe0,
+ 0x04, 0xe5, 0x00, 0x20, 0x05, 0x20, 0xe5, 0x00,
+ 0x00, 0x25, 0x00, 0xe5, 0x10, 0xa7, 0x00, 0x27,
+ 0x20, 0x26, 0x07, 0x06, 0x05, 0x07, 0x05, 0x07,
+ 0x06, 0x56, 0xe0, 0x01, 0xe9, 0x02, 0xe0, 0x3e,
+ 0xe5, 0x00, 0x20, 0xe5, 0x1f, 0x47, 0x66, 0x20,
+ 0x26, 0x67, 0x06, 0x05, 0x16, 0x05, 0x07, 0xe0,
+ 0x13, 0x05, 0xe6, 0x02, 0xe5, 0x20, 0xa6, 0x07,
+ 0x05, 0x66, 0xf6, 0x00, 0x06, 0xe0, 0x00, 0x05,
+ 0xa6, 0x27, 0x46, 0xe5, 0x26, 0xe6, 0x05, 0x07,
+ 0x26, 0x56, 0x05, 0x96, 0xe0, 0x05, 0xe5, 0x41,
+ 0xc0, 0xf6, 0x02, 0xe0, 0x80, 0x6e, 0xe5, 0x01,
+ 0x00, 0xe5, 0x1d, 0x07, 0xc6, 0x00, 0xa6, 0x07,
+ 0x06, 0x05, 0x96, 0xe0, 0x02, 0xe9, 0x02, 0xeb,
+ 0x0b, 0x40, 0x36, 0xe5, 0x16, 0x20, 0xe6, 0x0e,
+ 0x00, 0x07, 0xc6, 0x07, 0x26, 0x07, 0x26, 0xe0,
+ 0x41, 0xc5, 0x00, 0x25, 0x00, 0xe5, 0x1e, 0xa6,
+ 0x40, 0x06, 0x00, 0x26, 0x00, 0xc6, 0x05, 0x06,
+ 0xe0, 0x00, 0xe9, 0x02, 0xa0, 0xa5, 0x00, 0x25,
+ 0x00, 0xe5, 0x18, 0x87, 0x00, 0x26, 0x00, 0x27,
+ 0x06, 0x07, 0x06, 0x05, 0xc0, 0xe9, 0x02, 0xe0,
+ 0x80, 0xae, 0xe5, 0x0b, 0x26, 0x27, 0x36, 0xc0,
+ 0x26, 0x05, 0x07, 0xe5, 0x05, 0x00, 0xe5, 0x1a,
+ 0x27, 0x86, 0x40, 0x27, 0x06, 0x07, 0x06, 0xf6,
+ 0x05, 0xe9, 0x02, 0xe0, 0x4e, 0x05, 0xe0, 0x07,
+ 0xeb, 0x0d, 0xef, 0x00, 0x6d, 0xef, 0x09, 0xe0,
+ 0x05, 0x16, 0xe5, 0x83, 0x12, 0xe0, 0x5e, 0xea,
+ 0x67, 0x00, 0x96, 0xe0, 0x03, 0xe5, 0x80, 0x3c,
+ 0xe0, 0x89, 0xc4, 0xe5, 0x59, 0x36, 0xe0, 0x05,
+ 0xe5, 0x83, 0xa8, 0xfb, 0x08, 0x06, 0xa5, 0xe6,
+ 0x07, 0xe0, 0x8f, 0x22, 0xe5, 0x81, 0xbf, 0xe0,
+ 0xa1, 0x31, 0xe5, 0x81, 0xb1, 0xc0, 0xe5, 0x17,
+ 0x00, 0xe9, 0x02, 0x60, 0x36, 0xe5, 0x47, 0x00,
+ 0xe9, 0x02, 0xa0, 0xe5, 0x16, 0x20, 0x86, 0x16,
+ 0xe0, 0x02, 0xe5, 0x28, 0xc6, 0x96, 0x6f, 0x64,
+ 0x16, 0x0f, 0xe0, 0x02, 0xe9, 0x02, 0x00, 0xcb,
+ 0x00, 0xe5, 0x0d, 0x80, 0xe5, 0x0b, 0xe0, 0x82,
+ 0x28, 0xe1, 0x18, 0xe2, 0x18, 0xeb, 0x0f, 0x76,
+ 0xe0, 0x5d, 0xe5, 0x43, 0x60, 0x06, 0x05, 0xe7,
+ 0x2f, 0xc0, 0x66, 0xe4, 0x05, 0xe0, 0x38, 0x24,
+ 0x16, 0x04, 0x06, 0xe0, 0x03, 0x27, 0xe0, 0x06,
+ 0xe5, 0x97, 0x70, 0xe0, 0x00, 0xe5, 0x84, 0x4e,
+ 0xe0, 0x22, 0xe5, 0x01, 0xe0, 0xa2, 0x5f, 0x64,
+ 0x00, 0xc4, 0x00, 0x24, 0x00, 0xe5, 0x80, 0x9b,
+ 0xe0, 0x07, 0x05, 0xe0, 0x15, 0x45, 0x20, 0x05,
+ 0xe0, 0x06, 0x65, 0xe0, 0x00, 0xe5, 0x81, 0x04,
+ 0xe0, 0x88, 0x7c, 0xe5, 0x63, 0x80, 0xe5, 0x05,
+ 0x40, 0xe5, 0x01, 0xc0, 0xe5, 0x02, 0x20, 0x0f,
+ 0x26, 0x16, 0x7b, 0xe0, 0x91, 0xd4, 0xe6, 0x26,
+ 0x20, 0xe6, 0x0f, 0xe0, 0x01, 0xef, 0x6c, 0xe0,
+ 0x34, 0xef, 0x80, 0x6e, 0xe0, 0x02, 0xef, 0x1f,
+ 0x20, 0xef, 0x34, 0x27, 0x46, 0x4f, 0xa7, 0xfb,
+ 0x00, 0xe6, 0x00, 0x2f, 0xc6, 0xef, 0x16, 0x66,
+ 0xef, 0x35, 0xe0, 0x0d, 0xef, 0x3a, 0x46, 0x0f,
+ 0xe0, 0x72, 0xeb, 0x0c, 0xe0, 0x04, 0xeb, 0x0c,
+ 0xe0, 0x04, 0xef, 0x4f, 0xe0, 0x01, 0xeb, 0x11,
+ 0xe0, 0x7f, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12,
+ 0xc2, 0x00, 0xe2, 0x0a, 0xe1, 0x12, 0xe2, 0x12,
+ 0x01, 0x00, 0x21, 0x20, 0x01, 0x20, 0x21, 0x20,
+ 0x61, 0x00, 0xe1, 0x00, 0x62, 0x00, 0x02, 0x00,
+ 0xc2, 0x00, 0xe2, 0x03, 0xe1, 0x12, 0xe2, 0x12,
+ 0x21, 0x00, 0x61, 0x20, 0xe1, 0x00, 0x00, 0xc1,
+ 0x00, 0xe2, 0x12, 0x21, 0x00, 0x61, 0x00, 0x81,
+ 0x00, 0x01, 0x40, 0xc1, 0x00, 0xe2, 0x12, 0xe1,
+ 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1,
+ 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1,
+ 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x14, 0x20,
0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1,
- 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0x3f, 0x20,
- 0xe9, 0x2a, 0xef, 0x81, 0x78, 0xe6, 0x2f, 0x6f,
- 0xe6, 0x2a, 0xef, 0x00, 0x06, 0xef, 0x06, 0x06,
- 0x2f, 0x96, 0xe0, 0x07, 0x86, 0x00, 0xe6, 0x07,
- 0xe0, 0x83, 0xc8, 0xe2, 0x02, 0x05, 0xe2, 0x0c,
- 0xe0, 0x80, 0x59, 0xc6, 0x00, 0xe6, 0x09, 0x20,
- 0xc6, 0x00, 0x26, 0x00, 0x86, 0xe0, 0x80, 0x4d,
- 0xe5, 0x25, 0x40, 0xc6, 0xc4, 0x20, 0xe9, 0x02,
- 0x60, 0x05, 0x0f, 0xe0, 0x80, 0xb8, 0xe5, 0x16,
- 0x06, 0xe0, 0x09, 0xe5, 0x24, 0x66, 0xe9, 0x02,
- 0x80, 0x0d, 0xe0, 0x84, 0x58, 0xc5, 0x00, 0x65,
- 0x00, 0x25, 0x00, 0xe5, 0x07, 0x00, 0xe5, 0x80,
- 0x3d, 0x20, 0xeb, 0x01, 0xc6, 0xe0, 0x21, 0xe1,
- 0x1a, 0xe2, 0x1a, 0xc6, 0x04, 0x60, 0xe9, 0x02,
- 0x60, 0x36, 0xe0, 0x82, 0x89, 0xeb, 0x33, 0x0f,
- 0x4b, 0x0d, 0x6b, 0xe0, 0x44, 0xeb, 0x25, 0x0f,
- 0xeb, 0x07, 0xe0, 0x80, 0x3a, 0x65, 0x00, 0xe5,
- 0x13, 0x00, 0x25, 0x00, 0x05, 0x20, 0x05, 0x00,
- 0xe5, 0x02, 0x00, 0x65, 0x00, 0x05, 0x00, 0x05,
- 0xa0, 0x05, 0x60, 0x05, 0x00, 0x05, 0x00, 0x05,
- 0x00, 0x45, 0x00, 0x25, 0x00, 0x05, 0x20, 0x05,
- 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05,
- 0x00, 0x25, 0x00, 0x05, 0x20, 0x65, 0x00, 0xc5,
- 0x00, 0x65, 0x00, 0x65, 0x00, 0x05, 0x00, 0xe5,
- 0x02, 0x00, 0xe5, 0x09, 0x80, 0x45, 0x00, 0x85,
- 0x00, 0xe5, 0x09, 0xe0, 0x2c, 0x2c, 0xe0, 0x80,
- 0x86, 0xef, 0x24, 0x60, 0xef, 0x5c, 0xe0, 0x04,
- 0xef, 0x07, 0x20, 0xef, 0x07, 0x00, 0xef, 0x07,
- 0x00, 0xef, 0x1d, 0xe0, 0x02, 0xeb, 0x05, 0xef,
- 0x80, 0x19, 0xe0, 0x30, 0xef, 0x15, 0xe0, 0x05,
- 0xef, 0x24, 0x60, 0xef, 0x01, 0xc0, 0x2f, 0xe0,
- 0x06, 0xaf, 0xe0, 0x80, 0x12, 0xef, 0x80, 0x73,
- 0x8e, 0xef, 0x82, 0x50, 0x80, 0xef, 0x08, 0x40,
- 0xef, 0x05, 0x40, 0xef, 0x6c, 0xe0, 0x04, 0xef,
- 0x51, 0xc0, 0xef, 0x04, 0x60, 0x0f, 0xe0, 0x07,
- 0xef, 0x04, 0x60, 0xef, 0x30, 0xe0, 0x00, 0xef,
- 0x02, 0xa0, 0xef, 0x20, 0xe0, 0x00, 0xef, 0x16,
- 0x20, 0x2f, 0xe0, 0x46, 0xef, 0x80, 0xcc, 0xe0,
- 0x04, 0xef, 0x06, 0x20, 0x8f, 0x40, 0x8f, 0x40,
- 0xcf, 0xe0, 0x01, 0xef, 0x15, 0x40, 0xef, 0x03,
- 0x80, 0xaf, 0xe0, 0x02, 0xef, 0x02, 0xa0, 0xef,
- 0x00, 0xe0, 0x00, 0xcf, 0xe0, 0x01, 0xef, 0x80,
- 0x0b, 0x00, 0xef, 0x2f, 0xe0, 0x1d, 0xe9, 0x02,
- 0xe0, 0x83, 0x7e, 0xe5, 0xc0, 0x66, 0x58, 0xe0,
- 0x18, 0xe5, 0x8f, 0xb1, 0xc0, 0xe5, 0x80, 0x56,
- 0x20, 0xe5, 0x95, 0xfa, 0xe0, 0x06, 0xe5, 0x9c,
- 0xa9, 0xe0, 0x8b, 0x97, 0xe5, 0x81, 0x96, 0xe0,
- 0x85, 0x5a, 0xe5, 0x92, 0xc3, 0xe0, 0xca, 0xac,
- 0x2e, 0x1b, 0xe0, 0x16, 0xfb, 0x58, 0xe0, 0x78,
- 0xe6, 0x80, 0x68, 0xe0, 0xc0, 0xbd, 0x88, 0xfd,
- 0xc0, 0xbf, 0x76, 0x20, 0xfd, 0xc0, 0xbf, 0x76,
- 0x20,
+ 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11,
+ 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c,
+ 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2,
+ 0x11, 0x0c, 0xa2, 0x3f, 0x20, 0xe9, 0x2a, 0xef,
+ 0x81, 0x78, 0xe6, 0x2f, 0x6f, 0xe6, 0x2a, 0xef,
+ 0x00, 0x06, 0xef, 0x06, 0x06, 0x2f, 0x96, 0xe0,
+ 0x07, 0x86, 0x00, 0xe6, 0x07, 0xe0, 0x83, 0xc8,
+ 0xe2, 0x02, 0x05, 0xe2, 0x0c, 0xa0, 0xa2, 0xe0,
+ 0x80, 0x4d, 0xc6, 0x00, 0xe6, 0x09, 0x20, 0xc6,
+ 0x00, 0x26, 0x00, 0x86, 0x80, 0xe4, 0x36, 0xe0,
+ 0x19, 0x06, 0xe0, 0x68, 0xe5, 0x25, 0x40, 0xc6,
+ 0xc4, 0x20, 0xe9, 0x02, 0x60, 0x05, 0x0f, 0xe0,
+ 0x80, 0xb8, 0xe5, 0x16, 0x06, 0xe0, 0x09, 0xe5,
+ 0x24, 0x66, 0xe9, 0x02, 0x80, 0x0d, 0xe0, 0x81,
+ 0x48, 0xe5, 0x13, 0x04, 0x66, 0xe9, 0x02, 0xe0,
+ 0x82, 0x5e, 0xc5, 0x00, 0x65, 0x00, 0x25, 0x00,
+ 0xe5, 0x07, 0x00, 0xe5, 0x80, 0x3d, 0x20, 0xeb,
+ 0x01, 0xc6, 0xe0, 0x21, 0xe1, 0x1a, 0xe2, 0x1a,
+ 0xc6, 0x04, 0x60, 0xe9, 0x02, 0x60, 0x36, 0xe0,
+ 0x82, 0x89, 0xeb, 0x33, 0x0f, 0x4b, 0x0d, 0x6b,
+ 0xe0, 0x44, 0xeb, 0x25, 0x0f, 0xeb, 0x07, 0xe0,
+ 0x80, 0x3a, 0x65, 0x00, 0xe5, 0x13, 0x00, 0x25,
+ 0x00, 0x05, 0x20, 0x05, 0x00, 0xe5, 0x02, 0x00,
+ 0x65, 0x00, 0x05, 0x00, 0x05, 0xa0, 0x05, 0x60,
+ 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x45, 0x00,
+ 0x25, 0x00, 0x05, 0x20, 0x05, 0x00, 0x05, 0x00,
+ 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x25, 0x00,
+ 0x05, 0x20, 0x65, 0x00, 0xc5, 0x00, 0x65, 0x00,
+ 0x65, 0x00, 0x05, 0x00, 0xe5, 0x02, 0x00, 0xe5,
+ 0x09, 0x80, 0x45, 0x00, 0x85, 0x00, 0xe5, 0x09,
+ 0xe0, 0x2c, 0x2c, 0xe0, 0x80, 0x86, 0xef, 0x24,
+ 0x60, 0xef, 0x5c, 0xe0, 0x04, 0xef, 0x07, 0x20,
+ 0xef, 0x07, 0x00, 0xef, 0x07, 0x00, 0xef, 0x1d,
+ 0xe0, 0x02, 0xeb, 0x05, 0xef, 0x80, 0x19, 0xe0,
+ 0x30, 0xef, 0x15, 0xe0, 0x05, 0xef, 0x24, 0x60,
+ 0xef, 0x01, 0xc0, 0x2f, 0xe0, 0x06, 0xaf, 0xe0,
+ 0x80, 0x12, 0xef, 0x80, 0x73, 0x8e, 0xef, 0x82,
+ 0x50, 0x60, 0xef, 0x09, 0x40, 0xef, 0x05, 0x40,
+ 0xef, 0x6f, 0x60, 0xef, 0x57, 0xa0, 0xef, 0x04,
+ 0x60, 0x0f, 0xe0, 0x07, 0xef, 0x04, 0x60, 0xef,
+ 0x30, 0xe0, 0x00, 0xef, 0x02, 0xa0, 0xef, 0x20,
+ 0xe0, 0x00, 0xef, 0x16, 0x20, 0x2f, 0xe0, 0x46,
+ 0xef, 0x80, 0xcc, 0xe0, 0x04, 0xef, 0x06, 0x20,
+ 0xef, 0x05, 0x40, 0xef, 0x01, 0xc0, 0xef, 0x26,
+ 0x00, 0xcf, 0xe0, 0x00, 0xef, 0x06, 0x60, 0xef,
+ 0x01, 0xc0, 0xef, 0x01, 0xc0, 0xef, 0x80, 0x0b,
+ 0x00, 0xef, 0x2f, 0xe0, 0x1d, 0xe9, 0x02, 0xe0,
+ 0x83, 0x7e, 0xe5, 0xc0, 0x66, 0x58, 0xe0, 0x18,
+ 0xe5, 0x8f, 0xb2, 0xa0, 0xe5, 0x80, 0x56, 0x20,
+ 0xe5, 0x95, 0xfa, 0xe0, 0x06, 0xe5, 0x9c, 0xa9,
+ 0xe0, 0x8b, 0x97, 0xe5, 0x81, 0x96, 0xe0, 0x85,
+ 0x5a, 0xe5, 0x92, 0xc3, 0x80, 0xe5, 0x8f, 0xd8,
+ 0xe0, 0xca, 0x9b, 0xc9, 0x1b, 0xe0, 0x16, 0xfb,
+ 0x58, 0xe0, 0x78, 0xe6, 0x80, 0x68, 0xe0, 0xc0,
+ 0xbd, 0x88, 0xfd, 0xc0, 0xbf, 0x76, 0x20, 0xfd,
+ 0xc0, 0xbf, 0x76, 0x20,
};
typedef enum {
@@ -2868,6 +2966,7 @@ typedef enum {
UNICODE_SCRIPT_Kaithi,
UNICODE_SCRIPT_Kannada,
UNICODE_SCRIPT_Katakana,
+ UNICODE_SCRIPT_Kawi,
UNICODE_SCRIPT_Kayah_Li,
UNICODE_SCRIPT_Kharoshthi,
UNICODE_SCRIPT_Khmer,
@@ -2902,6 +3001,7 @@ typedef enum {
UNICODE_SCRIPT_Multani,
UNICODE_SCRIPT_Myanmar,
UNICODE_SCRIPT_Nabataean,
+ UNICODE_SCRIPT_Nag_Mundari,
UNICODE_SCRIPT_Nandinagari,
UNICODE_SCRIPT_New_Tai_Lue,
UNICODE_SCRIPT_Newa,
@@ -3033,6 +3133,7 @@ static const char unicode_script_name_table[] =
"Kaithi,Kthi" "\0"
"Kannada,Knda" "\0"
"Katakana,Kana" "\0"
+ "Kawi,Kawi" "\0"
"Kayah_Li,Kali" "\0"
"Kharoshthi,Khar" "\0"
"Khmer,Khmr" "\0"
@@ -3067,6 +3168,7 @@ static const char unicode_script_name_table[] =
"Multani,Mult" "\0"
"Myanmar,Mymr" "\0"
"Nabataean,Nbat" "\0"
+ "Nag_Mundari,Nagm" "\0"
"Nandinagari,Nand" "\0"
"New_Tai_Lue,Talu" "\0"
"Newa,Newa" "\0"
@@ -3134,12 +3236,12 @@ static const char unicode_script_name_table[] =
"Zanabazar_Square,Zanb" "\0"
;
-static const uint8_t unicode_script_table[2690] = {
- 0xc0, 0x19, 0x99, 0x46, 0x85, 0x19, 0x99, 0x46,
- 0xae, 0x19, 0x80, 0x46, 0x8e, 0x19, 0x80, 0x46,
- 0x84, 0x19, 0x96, 0x46, 0x80, 0x19, 0x9e, 0x46,
- 0x80, 0x19, 0xe1, 0x60, 0x46, 0xa6, 0x19, 0x84,
- 0x46, 0x84, 0x19, 0x81, 0x0d, 0x93, 0x19, 0xe0,
+static const uint8_t unicode_script_table[2720] = {
+ 0xc0, 0x19, 0x99, 0x47, 0x85, 0x19, 0x99, 0x47,
+ 0xae, 0x19, 0x80, 0x47, 0x8e, 0x19, 0x80, 0x47,
+ 0x84, 0x19, 0x96, 0x47, 0x80, 0x19, 0x9e, 0x47,
+ 0x80, 0x19, 0xe1, 0x60, 0x47, 0xa6, 0x19, 0x84,
+ 0x47, 0x84, 0x19, 0x81, 0x0d, 0x93, 0x19, 0xe0,
0x0f, 0x38, 0x83, 0x2c, 0x80, 0x19, 0x82, 0x2c,
0x01, 0x83, 0x2c, 0x80, 0x19, 0x80, 0x2c, 0x03,
0x80, 0x2c, 0x80, 0x19, 0x80, 0x2c, 0x80, 0x19,
@@ -3152,11 +3254,11 @@ static const uint8_t unicode_script_table[2690] = {
0x80, 0x19, 0x8d, 0x04, 0x80, 0x19, 0x82, 0x04,
0x80, 0x19, 0x9f, 0x04, 0x80, 0x19, 0x89, 0x04,
0x8a, 0x38, 0x99, 0x04, 0x80, 0x38, 0xe0, 0x0b,
- 0x04, 0x80, 0x19, 0xa1, 0x04, 0x8d, 0x89, 0x00,
- 0xbb, 0x89, 0x01, 0x82, 0x89, 0xaf, 0x04, 0xb1,
- 0x93, 0x0d, 0xba, 0x64, 0x01, 0x82, 0x64, 0xad,
- 0x7d, 0x01, 0x8e, 0x7d, 0x00, 0x9b, 0x51, 0x01,
- 0x80, 0x51, 0x00, 0x8a, 0x89, 0x04, 0x9e, 0x04,
+ 0x04, 0x80, 0x19, 0xa1, 0x04, 0x8d, 0x8b, 0x00,
+ 0xbb, 0x8b, 0x01, 0x82, 0x8b, 0xaf, 0x04, 0xb1,
+ 0x95, 0x0d, 0xba, 0x66, 0x01, 0x82, 0x66, 0xad,
+ 0x7f, 0x01, 0x8e, 0x7f, 0x00, 0x9b, 0x52, 0x01,
+ 0x80, 0x52, 0x00, 0x8a, 0x8b, 0x04, 0x9e, 0x04,
0x00, 0x81, 0x04, 0x05, 0xc9, 0x04, 0x80, 0x19,
0x9c, 0x04, 0xd0, 0x20, 0x83, 0x38, 0x8e, 0x20,
0x81, 0x19, 0x99, 0x20, 0x83, 0x0b, 0x00, 0x87,
@@ -3176,43 +3278,43 @@ static const uint8_t unicode_script_table[2690] = {
0x84, 0x2d, 0x01, 0x89, 0x2d, 0x00, 0x82, 0x2d,
0x00, 0x82, 0x2d, 0x01, 0x80, 0x2d, 0x0e, 0x83,
0x2d, 0x01, 0x8b, 0x2d, 0x06, 0x86, 0x2d, 0x00,
- 0x82, 0x72, 0x00, 0x87, 0x72, 0x01, 0x81, 0x72,
- 0x01, 0x95, 0x72, 0x00, 0x86, 0x72, 0x00, 0x81,
- 0x72, 0x00, 0x84, 0x72, 0x01, 0x88, 0x72, 0x01,
- 0x81, 0x72, 0x01, 0x82, 0x72, 0x06, 0x82, 0x72,
- 0x03, 0x81, 0x72, 0x00, 0x84, 0x72, 0x01, 0x91,
- 0x72, 0x09, 0x81, 0x90, 0x00, 0x85, 0x90, 0x02,
- 0x82, 0x90, 0x00, 0x83, 0x90, 0x02, 0x81, 0x90,
- 0x00, 0x80, 0x90, 0x00, 0x81, 0x90, 0x02, 0x81,
- 0x90, 0x02, 0x82, 0x90, 0x02, 0x8b, 0x90, 0x03,
- 0x84, 0x90, 0x02, 0x82, 0x90, 0x00, 0x83, 0x90,
- 0x01, 0x80, 0x90, 0x05, 0x80, 0x90, 0x0d, 0x94,
- 0x90, 0x04, 0x8c, 0x92, 0x00, 0x82, 0x92, 0x00,
- 0x96, 0x92, 0x00, 0x8f, 0x92, 0x01, 0x88, 0x92,
- 0x00, 0x82, 0x92, 0x00, 0x83, 0x92, 0x06, 0x81,
- 0x92, 0x00, 0x82, 0x92, 0x01, 0x80, 0x92, 0x01,
- 0x83, 0x92, 0x01, 0x89, 0x92, 0x06, 0x88, 0x92,
+ 0x82, 0x74, 0x00, 0x87, 0x74, 0x01, 0x81, 0x74,
+ 0x01, 0x95, 0x74, 0x00, 0x86, 0x74, 0x00, 0x81,
+ 0x74, 0x00, 0x84, 0x74, 0x01, 0x88, 0x74, 0x01,
+ 0x81, 0x74, 0x01, 0x82, 0x74, 0x06, 0x82, 0x74,
+ 0x03, 0x81, 0x74, 0x00, 0x84, 0x74, 0x01, 0x91,
+ 0x74, 0x09, 0x81, 0x92, 0x00, 0x85, 0x92, 0x02,
+ 0x82, 0x92, 0x00, 0x83, 0x92, 0x02, 0x81, 0x92,
+ 0x00, 0x80, 0x92, 0x00, 0x81, 0x92, 0x02, 0x81,
+ 0x92, 0x02, 0x82, 0x92, 0x02, 0x8b, 0x92, 0x03,
+ 0x84, 0x92, 0x02, 0x82, 0x92, 0x00, 0x83, 0x92,
+ 0x01, 0x80, 0x92, 0x05, 0x80, 0x92, 0x0d, 0x94,
+ 0x92, 0x04, 0x8c, 0x94, 0x00, 0x82, 0x94, 0x00,
+ 0x96, 0x94, 0x00, 0x8f, 0x94, 0x01, 0x88, 0x94,
+ 0x00, 0x82, 0x94, 0x00, 0x83, 0x94, 0x06, 0x81,
+ 0x94, 0x00, 0x82, 0x94, 0x01, 0x80, 0x94, 0x01,
+ 0x83, 0x94, 0x01, 0x89, 0x94, 0x06, 0x88, 0x94,
0x8c, 0x3d, 0x00, 0x82, 0x3d, 0x00, 0x96, 0x3d,
0x00, 0x89, 0x3d, 0x00, 0x84, 0x3d, 0x01, 0x88,
0x3d, 0x00, 0x82, 0x3d, 0x00, 0x83, 0x3d, 0x06,
0x81, 0x3d, 0x05, 0x81, 0x3d, 0x00, 0x83, 0x3d,
- 0x01, 0x89, 0x3d, 0x00, 0x81, 0x3d, 0x0c, 0x8c,
- 0x50, 0x00, 0x82, 0x50, 0x00, 0xb2, 0x50, 0x00,
- 0x82, 0x50, 0x00, 0x85, 0x50, 0x03, 0x8f, 0x50,
- 0x01, 0x99, 0x50, 0x00, 0x82, 0x83, 0x00, 0x91,
- 0x83, 0x02, 0x97, 0x83, 0x00, 0x88, 0x83, 0x00,
- 0x80, 0x83, 0x01, 0x86, 0x83, 0x02, 0x80, 0x83,
- 0x03, 0x85, 0x83, 0x00, 0x80, 0x83, 0x00, 0x87,
- 0x83, 0x05, 0x89, 0x83, 0x01, 0x82, 0x83, 0x0b,
- 0xb9, 0x94, 0x03, 0x80, 0x19, 0x9b, 0x94, 0x24,
- 0x81, 0x45, 0x00, 0x80, 0x45, 0x00, 0x84, 0x45,
- 0x00, 0x97, 0x45, 0x00, 0x80, 0x45, 0x00, 0x96,
- 0x45, 0x01, 0x84, 0x45, 0x00, 0x80, 0x45, 0x00,
- 0x85, 0x45, 0x01, 0x89, 0x45, 0x01, 0x83, 0x45,
- 0x1f, 0xc7, 0x95, 0x00, 0xa3, 0x95, 0x03, 0xa6,
- 0x95, 0x00, 0xa3, 0x95, 0x00, 0x8e, 0x95, 0x00,
- 0x86, 0x95, 0x83, 0x19, 0x81, 0x95, 0x24, 0xe0,
- 0x3f, 0x5f, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04,
+ 0x01, 0x89, 0x3d, 0x00, 0x82, 0x3d, 0x0b, 0x8c,
+ 0x51, 0x00, 0x82, 0x51, 0x00, 0xb2, 0x51, 0x00,
+ 0x82, 0x51, 0x00, 0x85, 0x51, 0x03, 0x8f, 0x51,
+ 0x01, 0x99, 0x51, 0x00, 0x82, 0x85, 0x00, 0x91,
+ 0x85, 0x02, 0x97, 0x85, 0x00, 0x88, 0x85, 0x00,
+ 0x80, 0x85, 0x01, 0x86, 0x85, 0x02, 0x80, 0x85,
+ 0x03, 0x85, 0x85, 0x00, 0x80, 0x85, 0x00, 0x87,
+ 0x85, 0x05, 0x89, 0x85, 0x01, 0x82, 0x85, 0x0b,
+ 0xb9, 0x96, 0x03, 0x80, 0x19, 0x9b, 0x96, 0x24,
+ 0x81, 0x46, 0x00, 0x80, 0x46, 0x00, 0x84, 0x46,
+ 0x00, 0x97, 0x46, 0x00, 0x80, 0x46, 0x00, 0x96,
+ 0x46, 0x01, 0x84, 0x46, 0x00, 0x80, 0x46, 0x00,
+ 0x86, 0x46, 0x00, 0x89, 0x46, 0x01, 0x83, 0x46,
+ 0x1f, 0xc7, 0x97, 0x00, 0xa3, 0x97, 0x03, 0xa6,
+ 0x97, 0x00, 0xa3, 0x97, 0x00, 0x8e, 0x97, 0x00,
+ 0x86, 0x97, 0x83, 0x19, 0x81, 0x97, 0x24, 0xe0,
+ 0x3f, 0x60, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04,
0x80, 0x28, 0x01, 0xaa, 0x28, 0x80, 0x19, 0x83,
0x28, 0xe0, 0x9f, 0x31, 0xc8, 0x27, 0x00, 0x83,
0x27, 0x01, 0x86, 0x27, 0x00, 0x80, 0x27, 0x00,
@@ -3222,32 +3324,32 @@ static const uint8_t unicode_script_table[2690] = {
0x8e, 0x27, 0x00, 0xb8, 0x27, 0x00, 0x83, 0x27,
0x01, 0xc2, 0x27, 0x01, 0x9f, 0x27, 0x02, 0x99,
0x27, 0x05, 0xd5, 0x17, 0x01, 0x85, 0x17, 0x01,
- 0xe2, 0x1f, 0x12, 0x9c, 0x67, 0x02, 0xca, 0x7c,
- 0x82, 0x19, 0x8a, 0x7c, 0x06, 0x95, 0x8a, 0x08,
- 0x80, 0x8a, 0x94, 0x33, 0x81, 0x19, 0x08, 0x93,
- 0x11, 0x0b, 0x8c, 0x8b, 0x00, 0x82, 0x8b, 0x00,
- 0x81, 0x8b, 0x0b, 0xdd, 0x41, 0x01, 0x89, 0x41,
- 0x05, 0x89, 0x41, 0x05, 0x81, 0x5c, 0x81, 0x19,
- 0x80, 0x5c, 0x80, 0x19, 0x93, 0x5c, 0x05, 0xd8,
- 0x5c, 0x06, 0xaa, 0x5c, 0x04, 0xc5, 0x12, 0x09,
- 0x9e, 0x48, 0x00, 0x8b, 0x48, 0x03, 0x8b, 0x48,
- 0x03, 0x80, 0x48, 0x02, 0x8b, 0x48, 0x9d, 0x8c,
- 0x01, 0x84, 0x8c, 0x0a, 0xab, 0x62, 0x03, 0x99,
- 0x62, 0x05, 0x8a, 0x62, 0x02, 0x81, 0x62, 0x9f,
- 0x41, 0x9b, 0x10, 0x01, 0x81, 0x10, 0xbe, 0x8d,
- 0x00, 0x9c, 0x8d, 0x01, 0x8a, 0x8d, 0x05, 0x89,
- 0x8d, 0x05, 0x8d, 0x8d, 0x01, 0x9e, 0x38, 0x30,
- 0xcc, 0x07, 0x02, 0xae, 0x07, 0x00, 0xbf, 0x87,
- 0xb3, 0x0a, 0x07, 0x83, 0x0a, 0xb7, 0x47, 0x02,
- 0x8e, 0x47, 0x02, 0x82, 0x47, 0xaf, 0x68, 0x88,
+ 0xe2, 0x1f, 0x12, 0x9c, 0x69, 0x02, 0xca, 0x7e,
+ 0x82, 0x19, 0x8a, 0x7e, 0x06, 0x95, 0x8c, 0x08,
+ 0x80, 0x8c, 0x94, 0x33, 0x81, 0x19, 0x08, 0x93,
+ 0x11, 0x0b, 0x8c, 0x8d, 0x00, 0x82, 0x8d, 0x00,
+ 0x81, 0x8d, 0x0b, 0xdd, 0x42, 0x01, 0x89, 0x42,
+ 0x05, 0x89, 0x42, 0x05, 0x81, 0x5d, 0x81, 0x19,
+ 0x80, 0x5d, 0x80, 0x19, 0x93, 0x5d, 0x05, 0xd8,
+ 0x5d, 0x06, 0xaa, 0x5d, 0x04, 0xc5, 0x12, 0x09,
+ 0x9e, 0x49, 0x00, 0x8b, 0x49, 0x03, 0x8b, 0x49,
+ 0x03, 0x80, 0x49, 0x02, 0x8b, 0x49, 0x9d, 0x8e,
+ 0x01, 0x84, 0x8e, 0x0a, 0xab, 0x64, 0x03, 0x99,
+ 0x64, 0x05, 0x8a, 0x64, 0x02, 0x81, 0x64, 0x9f,
+ 0x42, 0x9b, 0x10, 0x01, 0x81, 0x10, 0xbe, 0x8f,
+ 0x00, 0x9c, 0x8f, 0x01, 0x8a, 0x8f, 0x05, 0x89,
+ 0x8f, 0x05, 0x8d, 0x8f, 0x01, 0x9e, 0x38, 0x30,
+ 0xcc, 0x07, 0x02, 0xae, 0x07, 0x00, 0xbf, 0x89,
+ 0xb3, 0x0a, 0x07, 0x83, 0x0a, 0xb7, 0x48, 0x02,
+ 0x8e, 0x48, 0x02, 0x82, 0x48, 0xaf, 0x6a, 0x88,
0x1d, 0x06, 0xaa, 0x28, 0x01, 0x82, 0x28, 0x87,
- 0x87, 0x07, 0x82, 0x38, 0x80, 0x19, 0x8c, 0x38,
+ 0x89, 0x07, 0x82, 0x38, 0x80, 0x19, 0x8c, 0x38,
0x80, 0x19, 0x86, 0x38, 0x83, 0x19, 0x80, 0x38,
0x85, 0x19, 0x80, 0x38, 0x82, 0x19, 0x81, 0x38,
- 0x80, 0x19, 0x04, 0xa5, 0x46, 0x84, 0x2c, 0x80,
- 0x1d, 0xb0, 0x46, 0x84, 0x2c, 0x83, 0x46, 0x84,
- 0x2c, 0x8c, 0x46, 0x80, 0x1d, 0xc5, 0x46, 0x80,
- 0x2c, 0xbf, 0x38, 0xe0, 0x9f, 0x46, 0x95, 0x2c,
+ 0x80, 0x19, 0x04, 0xa5, 0x47, 0x84, 0x2c, 0x80,
+ 0x1d, 0xb0, 0x47, 0x84, 0x2c, 0x83, 0x47, 0x84,
+ 0x2c, 0x8c, 0x47, 0x80, 0x1d, 0xc5, 0x47, 0x80,
+ 0x2c, 0xbf, 0x38, 0xe0, 0x9f, 0x47, 0x95, 0x2c,
0x01, 0x85, 0x2c, 0x01, 0xa5, 0x2c, 0x01, 0x85,
0x2c, 0x01, 0x87, 0x2c, 0x00, 0x80, 0x2c, 0x00,
0x80, 0x2c, 0x00, 0x80, 0x2c, 0x00, 0x9e, 0x2c,
@@ -3255,18 +3357,18 @@ static const uint8_t unicode_script_table[2690] = {
0x2c, 0x01, 0x85, 0x2c, 0x00, 0x92, 0x2c, 0x01,
0x82, 0x2c, 0x00, 0x88, 0x2c, 0x00, 0x8b, 0x19,
0x81, 0x38, 0xd6, 0x19, 0x00, 0x8a, 0x19, 0x80,
- 0x46, 0x01, 0x8a, 0x19, 0x80, 0x46, 0x8e, 0x19,
- 0x00, 0x8c, 0x46, 0x02, 0xa0, 0x19, 0x0e, 0xa0,
+ 0x47, 0x01, 0x8a, 0x19, 0x80, 0x47, 0x8e, 0x19,
+ 0x00, 0x8c, 0x47, 0x02, 0xa0, 0x19, 0x0e, 0xa0,
0x38, 0x0e, 0xa5, 0x19, 0x80, 0x2c, 0x82, 0x19,
- 0x81, 0x46, 0x85, 0x19, 0x80, 0x46, 0x9a, 0x19,
- 0x80, 0x46, 0x90, 0x19, 0xa8, 0x46, 0x82, 0x19,
+ 0x81, 0x47, 0x85, 0x19, 0x80, 0x47, 0x9a, 0x19,
+ 0x80, 0x47, 0x90, 0x19, 0xa8, 0x47, 0x82, 0x19,
0x03, 0xe2, 0x36, 0x19, 0x18, 0x8a, 0x19, 0x14,
0xe3, 0x3f, 0x19, 0xe0, 0x9f, 0x0f, 0xe2, 0x13,
0x19, 0x01, 0x9f, 0x19, 0x00, 0xe0, 0x08, 0x19,
- 0xdf, 0x29, 0x9f, 0x46, 0xe0, 0x13, 0x1a, 0x04,
+ 0xdf, 0x29, 0x9f, 0x47, 0xe0, 0x13, 0x1a, 0x04,
0x86, 0x1a, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04,
- 0x80, 0x28, 0x01, 0xb7, 0x96, 0x06, 0x81, 0x96,
- 0x0d, 0x80, 0x96, 0x96, 0x27, 0x08, 0x86, 0x27,
+ 0x80, 0x28, 0x01, 0xb7, 0x98, 0x06, 0x81, 0x98,
+ 0x0d, 0x80, 0x98, 0x96, 0x27, 0x08, 0x86, 0x27,
0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86,
0x27, 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00,
0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x9f, 0x1d,
@@ -3282,27 +3384,27 @@ static const uint8_t unicode_script_table[2690] = {
0x9e, 0x31, 0x00, 0xbf, 0x19, 0x9e, 0x31, 0xd0,
0x19, 0xae, 0x3e, 0x80, 0x19, 0xd7, 0x3e, 0xe0,
0x47, 0x19, 0xf0, 0x09, 0x5f, 0x30, 0xbf, 0x19,
- 0xf0, 0x41, 0x9f, 0x30, 0xe4, 0x2c, 0xa0, 0x02,
- 0xb6, 0xa0, 0x08, 0xaf, 0x4b, 0xe0, 0xcb, 0x9b,
+ 0xf0, 0x41, 0x9f, 0x30, 0xe4, 0x2c, 0xa2, 0x02,
+ 0xb6, 0xa2, 0x08, 0xaf, 0x4c, 0xe0, 0xcb, 0x9d,
0x13, 0xdf, 0x1d, 0xd7, 0x08, 0x07, 0xa1, 0x19,
- 0xe0, 0x05, 0x46, 0x82, 0x19, 0xbf, 0x46, 0x04,
- 0x81, 0x46, 0x00, 0x80, 0x46, 0x00, 0x84, 0x46,
- 0x17, 0x8d, 0x46, 0xac, 0x88, 0x02, 0x89, 0x19,
- 0x05, 0xb7, 0x78, 0x07, 0xc5, 0x7e, 0x07, 0x8b,
- 0x7e, 0x05, 0x9f, 0x20, 0xad, 0x3f, 0x80, 0x19,
- 0x80, 0x3f, 0xa3, 0x7b, 0x0a, 0x80, 0x7b, 0x9c,
+ 0xe0, 0x05, 0x47, 0x82, 0x19, 0xbf, 0x47, 0x04,
+ 0x81, 0x47, 0x00, 0x80, 0x47, 0x00, 0x84, 0x47,
+ 0x17, 0x8d, 0x47, 0xac, 0x8a, 0x02, 0x89, 0x19,
+ 0x05, 0xb7, 0x7a, 0x07, 0xc5, 0x80, 0x07, 0x8b,
+ 0x80, 0x05, 0x9f, 0x20, 0xad, 0x40, 0x80, 0x19,
+ 0x80, 0x40, 0xa3, 0x7d, 0x0a, 0x80, 0x7d, 0x9c,
0x31, 0x02, 0xcd, 0x3b, 0x00, 0x80, 0x19, 0x89,
- 0x3b, 0x03, 0x81, 0x3b, 0x9e, 0x5f, 0x00, 0xb6,
+ 0x3b, 0x03, 0x81, 0x3b, 0x9e, 0x60, 0x00, 0xb6,
0x16, 0x08, 0x8d, 0x16, 0x01, 0x89, 0x16, 0x01,
- 0x83, 0x16, 0x9f, 0x5f, 0xc2, 0x8e, 0x17, 0x84,
- 0x8e, 0x96, 0x56, 0x09, 0x85, 0x27, 0x01, 0x85,
+ 0x83, 0x16, 0x9f, 0x60, 0xc2, 0x90, 0x17, 0x84,
+ 0x90, 0x96, 0x57, 0x09, 0x85, 0x27, 0x01, 0x85,
0x27, 0x01, 0x85, 0x27, 0x08, 0x86, 0x27, 0x00,
- 0x86, 0x27, 0x00, 0xaa, 0x46, 0x80, 0x19, 0x88,
- 0x46, 0x80, 0x2c, 0x83, 0x46, 0x81, 0x19, 0x03,
- 0xcf, 0x17, 0xad, 0x56, 0x01, 0x89, 0x56, 0x05,
+ 0x86, 0x27, 0x00, 0xaa, 0x47, 0x80, 0x19, 0x88,
+ 0x47, 0x80, 0x2c, 0x83, 0x47, 0x81, 0x19, 0x03,
+ 0xcf, 0x17, 0xad, 0x57, 0x01, 0x89, 0x57, 0x05,
0xf0, 0x1b, 0x43, 0x31, 0x0b, 0x96, 0x31, 0x03,
0xb0, 0x31, 0x70, 0x10, 0xa3, 0xe1, 0x0d, 0x30,
- 0x01, 0xe0, 0x09, 0x30, 0x25, 0x86, 0x46, 0x0b,
+ 0x01, 0xe0, 0x09, 0x30, 0x25, 0x86, 0x47, 0x0b,
0x84, 0x05, 0x04, 0x99, 0x35, 0x00, 0x84, 0x35,
0x00, 0x80, 0x35, 0x00, 0x81, 0x35, 0x00, 0x81,
0x35, 0x00, 0x89, 0x35, 0xe0, 0x12, 0x04, 0x0f,
@@ -3311,130 +3413,134 @@ static const uint8_t unicode_script_table[2690] = {
0x8f, 0x38, 0x89, 0x19, 0x05, 0x8d, 0x38, 0x81,
0x1d, 0xa2, 0x19, 0x00, 0x92, 0x19, 0x00, 0x83,
0x19, 0x03, 0x84, 0x04, 0x00, 0xe0, 0x26, 0x04,
- 0x01, 0x80, 0x19, 0x00, 0x9f, 0x19, 0x99, 0x46,
- 0x85, 0x19, 0x99, 0x46, 0x8a, 0x19, 0x89, 0x3e,
+ 0x01, 0x80, 0x19, 0x00, 0x9f, 0x19, 0x99, 0x47,
+ 0x85, 0x19, 0x99, 0x47, 0x8a, 0x19, 0x89, 0x3e,
0x80, 0x19, 0xac, 0x3e, 0x81, 0x19, 0x9e, 0x31,
0x02, 0x85, 0x31, 0x01, 0x85, 0x31, 0x01, 0x85,
0x31, 0x01, 0x82, 0x31, 0x02, 0x86, 0x19, 0x00,
- 0x86, 0x19, 0x09, 0x84, 0x19, 0x01, 0x8b, 0x4a,
- 0x00, 0x99, 0x4a, 0x00, 0x92, 0x4a, 0x00, 0x81,
- 0x4a, 0x00, 0x8e, 0x4a, 0x01, 0x8d, 0x4a, 0x21,
- 0xe0, 0x1a, 0x4a, 0x04, 0x82, 0x19, 0x03, 0xac,
+ 0x86, 0x19, 0x09, 0x84, 0x19, 0x01, 0x8b, 0x4b,
+ 0x00, 0x99, 0x4b, 0x00, 0x92, 0x4b, 0x00, 0x81,
+ 0x4b, 0x00, 0x8e, 0x4b, 0x01, 0x8d, 0x4b, 0x21,
+ 0xe0, 0x1a, 0x4b, 0x04, 0x82, 0x19, 0x03, 0xac,
0x19, 0x02, 0x88, 0x19, 0xce, 0x2c, 0x00, 0x8c,
0x19, 0x02, 0x80, 0x2c, 0x2e, 0xac, 0x19, 0x80,
- 0x38, 0x60, 0x21, 0x9c, 0x4c, 0x02, 0xb0, 0x13,
- 0x0e, 0x80, 0x38, 0x9a, 0x19, 0x03, 0xa3, 0x6a,
- 0x08, 0x82, 0x6a, 0x9a, 0x2a, 0x04, 0xaa, 0x6c,
- 0x04, 0x9d, 0x9a, 0x00, 0x80, 0x9a, 0xa3, 0x6d,
- 0x03, 0x8d, 0x6d, 0x29, 0xcf, 0x1f, 0xaf, 0x80,
- 0x9d, 0x74, 0x01, 0x89, 0x74, 0x05, 0xa3, 0x73,
- 0x03, 0xa3, 0x73, 0x03, 0xa7, 0x25, 0x07, 0xb3,
- 0x14, 0x0a, 0x80, 0x14, 0x8a, 0x9c, 0x00, 0x8e,
- 0x9c, 0x00, 0x86, 0x9c, 0x00, 0x81, 0x9c, 0x00,
- 0x8a, 0x9c, 0x00, 0x8e, 0x9c, 0x00, 0x86, 0x9c,
- 0x00, 0x81, 0x9c, 0x42, 0xe0, 0xd6, 0x49, 0x08,
- 0x95, 0x49, 0x09, 0x87, 0x49, 0x17, 0x85, 0x46,
- 0x00, 0xa9, 0x46, 0x00, 0x88, 0x46, 0x44, 0x85,
+ 0x38, 0x60, 0x21, 0x9c, 0x4d, 0x02, 0xb0, 0x13,
+ 0x0e, 0x80, 0x38, 0x9a, 0x19, 0x03, 0xa3, 0x6c,
+ 0x08, 0x82, 0x6c, 0x9a, 0x2a, 0x04, 0xaa, 0x6e,
+ 0x04, 0x9d, 0x9c, 0x00, 0x80, 0x9c, 0xa3, 0x6f,
+ 0x03, 0x8d, 0x6f, 0x29, 0xcf, 0x1f, 0xaf, 0x82,
+ 0x9d, 0x76, 0x01, 0x89, 0x76, 0x05, 0xa3, 0x75,
+ 0x03, 0xa3, 0x75, 0x03, 0xa7, 0x25, 0x07, 0xb3,
+ 0x14, 0x0a, 0x80, 0x14, 0x8a, 0x9e, 0x00, 0x8e,
+ 0x9e, 0x00, 0x86, 0x9e, 0x00, 0x81, 0x9e, 0x00,
+ 0x8a, 0x9e, 0x00, 0x8e, 0x9e, 0x00, 0x86, 0x9e,
+ 0x00, 0x81, 0x9e, 0x42, 0xe0, 0xd6, 0x4a, 0x08,
+ 0x95, 0x4a, 0x09, 0x87, 0x4a, 0x17, 0x85, 0x47,
+ 0x00, 0xa9, 0x47, 0x00, 0x88, 0x47, 0x44, 0x85,
0x1c, 0x01, 0x80, 0x1c, 0x00, 0xab, 0x1c, 0x00,
0x81, 0x1c, 0x02, 0x80, 0x1c, 0x01, 0x80, 0x1c,
- 0x95, 0x37, 0x00, 0x88, 0x37, 0x9f, 0x76, 0x9e,
- 0x60, 0x07, 0x88, 0x60, 0x2f, 0x92, 0x34, 0x00,
- 0x81, 0x34, 0x04, 0x84, 0x34, 0x9b, 0x79, 0x02,
- 0x80, 0x79, 0x99, 0x4d, 0x04, 0x80, 0x4d, 0x3f,
- 0x9f, 0x59, 0x97, 0x58, 0x03, 0x93, 0x58, 0x01,
- 0xad, 0x58, 0x83, 0x40, 0x00, 0x81, 0x40, 0x04,
- 0x87, 0x40, 0x00, 0x82, 0x40, 0x00, 0x9c, 0x40,
- 0x01, 0x82, 0x40, 0x03, 0x89, 0x40, 0x06, 0x88,
- 0x40, 0x06, 0x9f, 0x6f, 0x9f, 0x6b, 0x1f, 0xa6,
- 0x52, 0x03, 0x8b, 0x52, 0x08, 0xb5, 0x06, 0x02,
+ 0x95, 0x37, 0x00, 0x88, 0x37, 0x9f, 0x78, 0x9e,
+ 0x61, 0x07, 0x88, 0x61, 0x2f, 0x92, 0x34, 0x00,
+ 0x81, 0x34, 0x04, 0x84, 0x34, 0x9b, 0x7b, 0x02,
+ 0x80, 0x7b, 0x99, 0x4e, 0x04, 0x80, 0x4e, 0x3f,
+ 0x9f, 0x5a, 0x97, 0x59, 0x03, 0x93, 0x59, 0x01,
+ 0xad, 0x59, 0x83, 0x41, 0x00, 0x81, 0x41, 0x04,
+ 0x87, 0x41, 0x00, 0x82, 0x41, 0x00, 0x9c, 0x41,
+ 0x01, 0x82, 0x41, 0x03, 0x89, 0x41, 0x06, 0x88,
+ 0x41, 0x06, 0x9f, 0x71, 0x9f, 0x6d, 0x1f, 0xa6,
+ 0x53, 0x03, 0x8b, 0x53, 0x08, 0xb5, 0x06, 0x02,
0x86, 0x06, 0x95, 0x3a, 0x01, 0x87, 0x3a, 0x92,
- 0x39, 0x04, 0x87, 0x39, 0x91, 0x7a, 0x06, 0x83,
- 0x7a, 0x0b, 0x86, 0x7a, 0x4f, 0xc8, 0x70, 0x36,
- 0xb2, 0x69, 0x0c, 0xb2, 0x69, 0x06, 0x85, 0x69,
+ 0x39, 0x04, 0x87, 0x39, 0x91, 0x7c, 0x06, 0x83,
+ 0x7c, 0x0b, 0x86, 0x7c, 0x4f, 0xc8, 0x72, 0x36,
+ 0xb2, 0x6b, 0x0c, 0xb2, 0x6b, 0x06, 0x85, 0x6b,
0xa7, 0x32, 0x07, 0x89, 0x32, 0x60, 0xc5, 0x9e,
- 0x04, 0x00, 0xa9, 0x9f, 0x00, 0x82, 0x9f, 0x01,
- 0x81, 0x9f, 0x4d, 0xa7, 0x6e, 0x07, 0xa9, 0x84,
- 0x15, 0x99, 0x71, 0x25, 0x9b, 0x18, 0x13, 0x96,
- 0x26, 0x08, 0xcd, 0x0e, 0x03, 0xa3, 0x0e, 0x08,
- 0x80, 0x0e, 0xc2, 0x3c, 0x09, 0x80, 0x3c, 0x01,
- 0x98, 0x85, 0x06, 0x89, 0x85, 0x05, 0xb4, 0x15,
- 0x00, 0x91, 0x15, 0x07, 0xa6, 0x4f, 0x08, 0xdf,
- 0x7f, 0x00, 0x93, 0x83, 0x0a, 0x91, 0x42, 0x00,
- 0xab, 0x42, 0x40, 0x86, 0x5e, 0x00, 0x80, 0x5e,
- 0x00, 0x83, 0x5e, 0x00, 0x8e, 0x5e, 0x00, 0x8a,
- 0x5e, 0x05, 0xba, 0x44, 0x04, 0x89, 0x44, 0x05,
- 0x83, 0x2b, 0x00, 0x87, 0x2b, 0x01, 0x81, 0x2b,
- 0x01, 0x95, 0x2b, 0x00, 0x86, 0x2b, 0x00, 0x81,
- 0x2b, 0x00, 0x84, 0x2b, 0x00, 0x80, 0x38, 0x88,
- 0x2b, 0x01, 0x81, 0x2b, 0x01, 0x82, 0x2b, 0x01,
- 0x80, 0x2b, 0x05, 0x80, 0x2b, 0x04, 0x86, 0x2b,
- 0x01, 0x86, 0x2b, 0x02, 0x84, 0x2b, 0x60, 0x2a,
- 0xdb, 0x63, 0x00, 0x84, 0x63, 0x1d, 0xc7, 0x97,
- 0x07, 0x89, 0x97, 0x60, 0x45, 0xb5, 0x81, 0x01,
- 0xa5, 0x81, 0x21, 0xc4, 0x5b, 0x0a, 0x89, 0x5b,
- 0x05, 0x8c, 0x5c, 0x12, 0xb9, 0x8f, 0x05, 0x89,
- 0x8f, 0x35, 0x9a, 0x02, 0x01, 0x8e, 0x02, 0x03,
- 0x96, 0x02, 0x60, 0x58, 0xbb, 0x22, 0x60, 0x03,
- 0xd2, 0x9e, 0x0b, 0x80, 0x9e, 0x86, 0x21, 0x01,
- 0x80, 0x21, 0x01, 0x87, 0x21, 0x00, 0x81, 0x21,
- 0x00, 0x9d, 0x21, 0x00, 0x81, 0x21, 0x01, 0x8b,
- 0x21, 0x08, 0x89, 0x21, 0x45, 0x87, 0x61, 0x01,
- 0xad, 0x61, 0x01, 0x8a, 0x61, 0x1a, 0xc7, 0xa1,
- 0x07, 0xd2, 0x86, 0x0c, 0x8f, 0x12, 0xb8, 0x77,
- 0x60, 0xa6, 0x88, 0x0c, 0x00, 0xac, 0x0c, 0x00,
- 0x8d, 0x0c, 0x09, 0x9c, 0x0c, 0x02, 0x9f, 0x53,
- 0x01, 0x95, 0x53, 0x00, 0x8d, 0x53, 0x48, 0x86,
- 0x54, 0x00, 0x81, 0x54, 0x00, 0xab, 0x54, 0x02,
- 0x80, 0x54, 0x00, 0x81, 0x54, 0x00, 0x88, 0x54,
- 0x07, 0x89, 0x54, 0x05, 0x85, 0x2e, 0x00, 0x81,
- 0x2e, 0x00, 0xa4, 0x2e, 0x00, 0x81, 0x2e, 0x00,
- 0x85, 0x2e, 0x06, 0x89, 0x2e, 0x60, 0xd5, 0x98,
- 0x4e, 0x60, 0x56, 0x80, 0x4b, 0x0e, 0xb1, 0x90,
- 0x0c, 0x80, 0x90, 0xe3, 0x39, 0x1b, 0x60, 0x05,
- 0xe0, 0x0e, 0x1b, 0x00, 0x84, 0x1b, 0x0a, 0xe0,
- 0x63, 0x1b, 0x69, 0xeb, 0xe0, 0x02, 0x1e, 0x0c,
- 0xe3, 0xce, 0x24, 0x00, 0x88, 0x24, 0x6f, 0x66,
- 0xe1, 0xe6, 0x03, 0x70, 0x11, 0x58, 0xe1, 0xd8,
- 0x08, 0x06, 0x9e, 0x5d, 0x00, 0x89, 0x5d, 0x03,
- 0x81, 0x5d, 0xce, 0x98, 0x00, 0x89, 0x98, 0x05,
- 0x9d, 0x09, 0x01, 0x85, 0x09, 0x09, 0xc5, 0x75,
- 0x09, 0x89, 0x75, 0x00, 0x86, 0x75, 0x00, 0x94,
- 0x75, 0x04, 0x92, 0x75, 0x62, 0x4f, 0xda, 0x55,
- 0x60, 0x04, 0xca, 0x5a, 0x03, 0xb8, 0x5a, 0x06,
- 0x90, 0x5a, 0x3f, 0x80, 0x91, 0x80, 0x65, 0x81,
- 0x30, 0x80, 0x43, 0x0a, 0x81, 0x30, 0x0d, 0xf0,
- 0x07, 0x97, 0x91, 0x07, 0xe2, 0x9f, 0x91, 0xe1,
- 0x75, 0x43, 0x29, 0x88, 0x91, 0x70, 0x12, 0x86,
- 0x83, 0x3e, 0x00, 0x86, 0x3e, 0x00, 0x81, 0x3e,
- 0x00, 0x80, 0x3e, 0xe0, 0xbe, 0x36, 0x82, 0x3e,
- 0x2c, 0x82, 0x36, 0x10, 0x83, 0x3e, 0x07, 0xe1,
- 0x2b, 0x65, 0x68, 0xa3, 0xe0, 0x0a, 0x23, 0x04,
+ 0x04, 0x00, 0xa9, 0xa1, 0x00, 0x82, 0xa1, 0x01,
+ 0x81, 0xa1, 0x4a, 0x82, 0x04, 0xa7, 0x70, 0x07,
+ 0xa9, 0x86, 0x15, 0x99, 0x73, 0x25, 0x9b, 0x18,
+ 0x13, 0x96, 0x26, 0x08, 0xcd, 0x0e, 0x03, 0xa3,
+ 0x0e, 0x08, 0x80, 0x0e, 0xc2, 0x3c, 0x09, 0x80,
+ 0x3c, 0x01, 0x98, 0x87, 0x06, 0x89, 0x87, 0x05,
+ 0xb4, 0x15, 0x00, 0x91, 0x15, 0x07, 0xa6, 0x50,
+ 0x08, 0xdf, 0x81, 0x00, 0x93, 0x85, 0x0a, 0x91,
+ 0x43, 0x00, 0xae, 0x43, 0x3d, 0x86, 0x5f, 0x00,
+ 0x80, 0x5f, 0x00, 0x83, 0x5f, 0x00, 0x8e, 0x5f,
+ 0x00, 0x8a, 0x5f, 0x05, 0xba, 0x45, 0x04, 0x89,
+ 0x45, 0x05, 0x83, 0x2b, 0x00, 0x87, 0x2b, 0x01,
+ 0x81, 0x2b, 0x01, 0x95, 0x2b, 0x00, 0x86, 0x2b,
+ 0x00, 0x81, 0x2b, 0x00, 0x84, 0x2b, 0x00, 0x80,
+ 0x38, 0x88, 0x2b, 0x01, 0x81, 0x2b, 0x01, 0x82,
+ 0x2b, 0x01, 0x80, 0x2b, 0x05, 0x80, 0x2b, 0x04,
+ 0x86, 0x2b, 0x01, 0x86, 0x2b, 0x02, 0x84, 0x2b,
+ 0x60, 0x2a, 0xdb, 0x65, 0x00, 0x84, 0x65, 0x1d,
+ 0xc7, 0x99, 0x07, 0x89, 0x99, 0x60, 0x45, 0xb5,
+ 0x83, 0x01, 0xa5, 0x83, 0x21, 0xc4, 0x5c, 0x0a,
+ 0x89, 0x5c, 0x05, 0x8c, 0x5d, 0x12, 0xb9, 0x91,
+ 0x05, 0x89, 0x91, 0x35, 0x9a, 0x02, 0x01, 0x8e,
+ 0x02, 0x03, 0x96, 0x02, 0x60, 0x58, 0xbb, 0x22,
+ 0x60, 0x03, 0xd2, 0xa0, 0x0b, 0x80, 0xa0, 0x86,
+ 0x21, 0x01, 0x80, 0x21, 0x01, 0x87, 0x21, 0x00,
+ 0x81, 0x21, 0x00, 0x9d, 0x21, 0x00, 0x81, 0x21,
+ 0x01, 0x8b, 0x21, 0x08, 0x89, 0x21, 0x45, 0x87,
+ 0x63, 0x01, 0xad, 0x63, 0x01, 0x8a, 0x63, 0x1a,
+ 0xc7, 0xa3, 0x07, 0xd2, 0x88, 0x0c, 0x8f, 0x12,
+ 0xb8, 0x79, 0x06, 0x89, 0x20, 0x60, 0x95, 0x88,
+ 0x0c, 0x00, 0xac, 0x0c, 0x00, 0x8d, 0x0c, 0x09,
+ 0x9c, 0x0c, 0x02, 0x9f, 0x54, 0x01, 0x95, 0x54,
+ 0x00, 0x8d, 0x54, 0x48, 0x86, 0x55, 0x00, 0x81,
+ 0x55, 0x00, 0xab, 0x55, 0x02, 0x80, 0x55, 0x00,
+ 0x81, 0x55, 0x00, 0x88, 0x55, 0x07, 0x89, 0x55,
+ 0x05, 0x85, 0x2e, 0x00, 0x81, 0x2e, 0x00, 0xa4,
+ 0x2e, 0x00, 0x81, 0x2e, 0x00, 0x85, 0x2e, 0x06,
+ 0x89, 0x2e, 0x60, 0xd5, 0x98, 0x4f, 0x06, 0x90,
+ 0x3f, 0x00, 0xa8, 0x3f, 0x02, 0x9b, 0x3f, 0x55,
+ 0x80, 0x4c, 0x0e, 0xb1, 0x92, 0x0c, 0x80, 0x92,
+ 0xe3, 0x39, 0x1b, 0x60, 0x05, 0xe0, 0x0e, 0x1b,
+ 0x00, 0x84, 0x1b, 0x0a, 0xe0, 0x63, 0x1b, 0x69,
+ 0xeb, 0xe0, 0x02, 0x1e, 0x0c, 0xe3, 0xf5, 0x24,
+ 0x6f, 0x49, 0xe1, 0xe6, 0x03, 0x70, 0x11, 0x58,
+ 0xe1, 0xd8, 0x08, 0x06, 0x9e, 0x5e, 0x00, 0x89,
+ 0x5e, 0x03, 0x81, 0x5e, 0xce, 0x9a, 0x00, 0x89,
+ 0x9a, 0x05, 0x9d, 0x09, 0x01, 0x85, 0x09, 0x09,
+ 0xc5, 0x77, 0x09, 0x89, 0x77, 0x00, 0x86, 0x77,
+ 0x00, 0x94, 0x77, 0x04, 0x92, 0x77, 0x62, 0x4f,
+ 0xda, 0x56, 0x60, 0x04, 0xca, 0x5b, 0x03, 0xb8,
+ 0x5b, 0x06, 0x90, 0x5b, 0x3f, 0x80, 0x93, 0x80,
+ 0x67, 0x81, 0x30, 0x80, 0x44, 0x0a, 0x81, 0x30,
+ 0x0d, 0xf0, 0x07, 0x97, 0x93, 0x07, 0xe2, 0x9f,
+ 0x93, 0xe1, 0x75, 0x44, 0x29, 0x88, 0x93, 0x70,
+ 0x12, 0x86, 0x83, 0x3e, 0x00, 0x86, 0x3e, 0x00,
+ 0x81, 0x3e, 0x00, 0x80, 0x3e, 0xe0, 0xbe, 0x36,
+ 0x82, 0x3e, 0x0e, 0x80, 0x36, 0x1c, 0x82, 0x36,
+ 0x01, 0x80, 0x3e, 0x0d, 0x83, 0x3e, 0x07, 0xe1,
+ 0x2b, 0x67, 0x68, 0xa3, 0xe0, 0x0a, 0x23, 0x04,
0x8c, 0x23, 0x02, 0x88, 0x23, 0x06, 0x89, 0x23,
0x01, 0x83, 0x23, 0x83, 0x19, 0x70, 0x01, 0xfb,
0xad, 0x38, 0x01, 0x96, 0x38, 0x08, 0xe0, 0x13,
0x19, 0x3b, 0xe0, 0x95, 0x19, 0x09, 0xa6, 0x19,
0x01, 0xbd, 0x19, 0x82, 0x38, 0x90, 0x19, 0x87,
0x38, 0x81, 0x19, 0x86, 0x38, 0x9d, 0x19, 0x83,
- 0x38, 0xbc, 0x19, 0x14, 0xc5, 0x2c, 0x60, 0x39,
- 0x93, 0x19, 0x0b, 0xd6, 0x19, 0x08, 0x98, 0x19,
- 0x60, 0x26, 0xd4, 0x19, 0x00, 0xc6, 0x19, 0x00,
- 0x81, 0x19, 0x01, 0x80, 0x19, 0x01, 0x81, 0x19,
- 0x01, 0x83, 0x19, 0x00, 0x8b, 0x19, 0x00, 0x80,
- 0x19, 0x00, 0x86, 0x19, 0x00, 0xc0, 0x19, 0x00,
- 0x83, 0x19, 0x01, 0x87, 0x19, 0x00, 0x86, 0x19,
- 0x00, 0x9b, 0x19, 0x00, 0x83, 0x19, 0x00, 0x84,
- 0x19, 0x00, 0x80, 0x19, 0x02, 0x86, 0x19, 0x00,
- 0xe0, 0xf3, 0x19, 0x01, 0xe0, 0xc3, 0x19, 0x01,
- 0xb1, 0x19, 0xe2, 0x2b, 0x82, 0x0e, 0x84, 0x82,
- 0x00, 0x8e, 0x82, 0x63, 0xef, 0x9e, 0x46, 0x60,
- 0x80, 0x86, 0x29, 0x00, 0x90, 0x29, 0x01, 0x86,
- 0x29, 0x00, 0x81, 0x29, 0x00, 0x84, 0x29, 0x60,
- 0x74, 0xac, 0x66, 0x02, 0x8d, 0x66, 0x01, 0x89,
- 0x66, 0x03, 0x81, 0x66, 0x60, 0xdf, 0x9e, 0x99,
- 0x10, 0xb9, 0x9d, 0x04, 0x80, 0x9d, 0x64, 0x7f,
+ 0x38, 0xbc, 0x19, 0x14, 0xc5, 0x2c, 0x60, 0x19,
+ 0x93, 0x19, 0x0b, 0x93, 0x19, 0x0b, 0xd6, 0x19,
+ 0x08, 0x98, 0x19, 0x60, 0x26, 0xd4, 0x19, 0x00,
+ 0xc6, 0x19, 0x00, 0x81, 0x19, 0x01, 0x80, 0x19,
+ 0x01, 0x81, 0x19, 0x01, 0x83, 0x19, 0x00, 0x8b,
+ 0x19, 0x00, 0x80, 0x19, 0x00, 0x86, 0x19, 0x00,
+ 0xc0, 0x19, 0x00, 0x83, 0x19, 0x01, 0x87, 0x19,
+ 0x00, 0x86, 0x19, 0x00, 0x9b, 0x19, 0x00, 0x83,
+ 0x19, 0x00, 0x84, 0x19, 0x00, 0x80, 0x19, 0x02,
+ 0x86, 0x19, 0x00, 0xe0, 0xf3, 0x19, 0x01, 0xe0,
+ 0xc3, 0x19, 0x01, 0xb1, 0x19, 0xe2, 0x2b, 0x84,
+ 0x0e, 0x84, 0x84, 0x00, 0x8e, 0x84, 0x63, 0xef,
+ 0x9e, 0x47, 0x05, 0x85, 0x47, 0x60, 0x74, 0x86,
+ 0x29, 0x00, 0x90, 0x29, 0x01, 0x86, 0x29, 0x00,
+ 0x81, 0x29, 0x00, 0x84, 0x29, 0x04, 0xbd, 0x1d,
+ 0x20, 0x80, 0x1d, 0x60, 0x0f, 0xac, 0x68, 0x02,
+ 0x8d, 0x68, 0x01, 0x89, 0x68, 0x03, 0x81, 0x68,
+ 0x60, 0xdf, 0x9e, 0x9b, 0x10, 0xb9, 0x9f, 0x04,
+ 0x80, 0x9f, 0x61, 0x6f, 0xa9, 0x62, 0x62, 0x85,
0x86, 0x27, 0x00, 0x83, 0x27, 0x00, 0x81, 0x27,
- 0x00, 0x8e, 0x27, 0x00, 0xe0, 0x64, 0x57, 0x01,
- 0x8f, 0x57, 0x28, 0xcb, 0x01, 0x03, 0x89, 0x01,
+ 0x00, 0x8e, 0x27, 0x00, 0xe0, 0x64, 0x58, 0x01,
+ 0x8f, 0x58, 0x28, 0xcb, 0x01, 0x03, 0x89, 0x01,
0x03, 0x81, 0x01, 0x62, 0xb0, 0xc3, 0x19, 0x4b,
0xbc, 0x19, 0x60, 0x61, 0x83, 0x04, 0x00, 0x9a,
0x04, 0x00, 0x81, 0x04, 0x00, 0x80, 0x04, 0x01,
@@ -3455,86 +3561,85 @@ static const uint8_t unicode_script_table[2690] = {
0x19, 0x37, 0x99, 0x19, 0x80, 0x36, 0x81, 0x19,
0x0c, 0xab, 0x19, 0x03, 0x88, 0x19, 0x06, 0x81,
0x19, 0x0d, 0x85, 0x19, 0x60, 0x39, 0xe3, 0x77,
- 0x19, 0x04, 0x8f, 0x19, 0x02, 0x8c, 0x19, 0x02,
- 0xe0, 0x13, 0x19, 0x0b, 0xd8, 0x19, 0x06, 0x8b,
+ 0x19, 0x03, 0x90, 0x19, 0x02, 0x8c, 0x19, 0x02,
+ 0xe0, 0x16, 0x19, 0x03, 0xde, 0x19, 0x05, 0x8b,
0x19, 0x03, 0x80, 0x19, 0x0e, 0x8b, 0x19, 0x03,
0xb7, 0x19, 0x07, 0x89, 0x19, 0x05, 0xa7, 0x19,
0x07, 0x9d, 0x19, 0x01, 0x81, 0x19, 0x4d, 0xe0,
- 0xf3, 0x19, 0x0b, 0x8d, 0x19, 0x01, 0x84, 0x19,
- 0x02, 0x84, 0x19, 0x02, 0x86, 0x19, 0x08, 0x9c,
- 0x19, 0x02, 0x8a, 0x19, 0x04, 0x85, 0x19, 0x09,
- 0x89, 0x19, 0x05, 0x87, 0x19, 0x07, 0x86, 0x19,
- 0x08, 0xe0, 0x32, 0x19, 0x00, 0xb6, 0x19, 0x24,
- 0x89, 0x19, 0x63, 0xa5, 0xf0, 0x96, 0x7f, 0x30,
- 0x1f, 0xef, 0xd8, 0x30, 0x06, 0xe0, 0x7d, 0x30,
- 0x01, 0xf0, 0x06, 0x21, 0x30, 0x0d, 0xf0, 0x0c,
- 0xd0, 0x30, 0x6b, 0xbe, 0xe1, 0xbd, 0x30, 0x65,
- 0x81, 0xf0, 0x02, 0xea, 0x30, 0x7a, 0xdc, 0x55,
- 0x80, 0x19, 0x1d, 0xdf, 0x19, 0x60, 0x1f, 0xe0,
- 0x8f, 0x38,
+ 0xf3, 0x19, 0x0b, 0x8d, 0x19, 0x01, 0x8c, 0x19,
+ 0x02, 0x88, 0x19, 0x06, 0xad, 0x19, 0x00, 0x86,
+ 0x19, 0x07, 0x8d, 0x19, 0x03, 0x88, 0x19, 0x06,
+ 0x88, 0x19, 0x06, 0xe0, 0x32, 0x19, 0x00, 0xb6,
+ 0x19, 0x24, 0x89, 0x19, 0x63, 0xa5, 0xf0, 0x96,
+ 0x7f, 0x30, 0x1f, 0xef, 0xd9, 0x30, 0x05, 0xe0,
+ 0x7d, 0x30, 0x01, 0xf0, 0x06, 0x21, 0x30, 0x0d,
+ 0xf0, 0x0c, 0xd0, 0x30, 0x6b, 0xbe, 0xe1, 0xbd,
+ 0x30, 0x65, 0x81, 0xf0, 0x02, 0xea, 0x30, 0x04,
+ 0xef, 0xff, 0x30, 0x7a, 0xcb, 0xf0, 0x80, 0x19,
+ 0x1d, 0xdf, 0x19, 0x60, 0x1f, 0xe0, 0x8f, 0x38,
};
static const uint8_t unicode_script_ext_table[828] = {
0x82, 0xc1, 0x00, 0x00, 0x01, 0x2c, 0x01, 0x00,
- 0x00, 0x01, 0x2c, 0x1c, 0x00, 0x0c, 0x01, 0x46,
- 0x80, 0x92, 0x00, 0x00, 0x02, 0x1d, 0x6c, 0x00,
- 0x02, 0x1d, 0x29, 0x01, 0x02, 0x1d, 0x46, 0x00,
+ 0x00, 0x01, 0x2c, 0x1c, 0x00, 0x0c, 0x01, 0x47,
+ 0x80, 0x92, 0x00, 0x00, 0x02, 0x1d, 0x6e, 0x00,
+ 0x02, 0x1d, 0x29, 0x01, 0x02, 0x1d, 0x47, 0x00,
0x02, 0x1d, 0x29, 0x81, 0x03, 0x00, 0x00, 0x06,
- 0x04, 0x64, 0x32, 0x89, 0x93, 0x9f, 0x0d, 0x00,
- 0x00, 0x06, 0x04, 0x64, 0x32, 0x89, 0x93, 0x9f,
- 0x00, 0x03, 0x04, 0x89, 0x93, 0x01, 0x00, 0x00,
- 0x07, 0x01, 0x04, 0x64, 0x32, 0x89, 0x93, 0x9f,
- 0x1f, 0x00, 0x00, 0x09, 0x01, 0x04, 0x51, 0x52,
- 0x71, 0x7a, 0x32, 0x84, 0x89, 0x09, 0x00, 0x0a,
- 0x02, 0x04, 0x89, 0x09, 0x00, 0x09, 0x03, 0x04,
- 0x93, 0x9f, 0x05, 0x00, 0x00, 0x02, 0x04, 0x89,
+ 0x04, 0x66, 0x32, 0x8b, 0x95, 0xa1, 0x0d, 0x00,
+ 0x00, 0x06, 0x04, 0x66, 0x32, 0x8b, 0x95, 0xa1,
+ 0x00, 0x03, 0x04, 0x8b, 0x95, 0x01, 0x00, 0x00,
+ 0x07, 0x01, 0x04, 0x66, 0x32, 0x8b, 0x95, 0xa1,
+ 0x1f, 0x00, 0x00, 0x09, 0x01, 0x04, 0x52, 0x53,
+ 0x73, 0x7c, 0x32, 0x86, 0x8b, 0x09, 0x00, 0x0a,
+ 0x02, 0x04, 0x8b, 0x09, 0x00, 0x09, 0x03, 0x04,
+ 0x95, 0xa1, 0x05, 0x00, 0x00, 0x02, 0x04, 0x8b,
0x62, 0x00, 0x00, 0x02, 0x04, 0x32, 0x81, 0xfb,
0x00, 0x00, 0x0d, 0x0b, 0x20, 0x2b, 0x2d, 0x2f,
- 0x3d, 0x46, 0x50, 0x72, 0x7f, 0x90, 0x92, 0x97,
+ 0x3d, 0x47, 0x51, 0x74, 0x81, 0x92, 0x94, 0x99,
0x00, 0x0c, 0x0b, 0x20, 0x2b, 0x2d, 0x2f, 0x3d,
- 0x46, 0x50, 0x72, 0x90, 0x92, 0x97, 0x10, 0x00,
- 0x00, 0x14, 0x0b, 0x20, 0x22, 0x2e, 0x54, 0x2b,
- 0x2d, 0x2f, 0x3d, 0x4f, 0x50, 0x61, 0x72, 0x44,
- 0x83, 0x88, 0x8f, 0x90, 0x92, 0x97, 0x00, 0x15,
- 0x0b, 0x20, 0x22, 0x2e, 0x54, 0x2b, 0x2d, 0x2f,
- 0x3d, 0x48, 0x4f, 0x50, 0x61, 0x72, 0x44, 0x83,
- 0x88, 0x8f, 0x90, 0x92, 0x97, 0x09, 0x04, 0x20,
- 0x22, 0x3c, 0x4f, 0x75, 0x00, 0x09, 0x03, 0x0b,
- 0x15, 0x88, 0x75, 0x00, 0x09, 0x02, 0x2f, 0x5e,
- 0x75, 0x00, 0x09, 0x02, 0x2d, 0x42, 0x80, 0x75,
- 0x00, 0x0d, 0x02, 0x2b, 0x90, 0x80, 0x71, 0x00,
- 0x09, 0x02, 0x3d, 0x61, 0x82, 0xcf, 0x00, 0x09,
- 0x03, 0x15, 0x5f, 0x8c, 0x80, 0x30, 0x00, 0x00,
- 0x02, 0x28, 0x46, 0x85, 0xb8, 0x00, 0x01, 0x04,
- 0x11, 0x33, 0x8b, 0x8a, 0x80, 0x4a, 0x00, 0x01,
- 0x02, 0x5c, 0x78, 0x00, 0x00, 0x00, 0x02, 0x5c,
- 0x78, 0x84, 0x49, 0x00, 0x00, 0x04, 0x0b, 0x20,
+ 0x47, 0x51, 0x74, 0x92, 0x94, 0x99, 0x10, 0x00,
+ 0x00, 0x14, 0x0b, 0x20, 0x22, 0x2e, 0x55, 0x2b,
+ 0x2d, 0x2f, 0x3d, 0x50, 0x51, 0x63, 0x74, 0x45,
+ 0x85, 0x8a, 0x91, 0x92, 0x94, 0x99, 0x00, 0x15,
+ 0x0b, 0x20, 0x22, 0x2e, 0x55, 0x2b, 0x2d, 0x2f,
+ 0x3d, 0x49, 0x50, 0x51, 0x63, 0x74, 0x45, 0x85,
+ 0x8a, 0x91, 0x92, 0x94, 0x99, 0x09, 0x04, 0x20,
+ 0x22, 0x3c, 0x50, 0x75, 0x00, 0x09, 0x03, 0x0b,
+ 0x15, 0x8a, 0x75, 0x00, 0x09, 0x02, 0x2f, 0x5f,
+ 0x75, 0x00, 0x09, 0x02, 0x2d, 0x43, 0x80, 0x75,
+ 0x00, 0x0d, 0x02, 0x2b, 0x92, 0x80, 0x71, 0x00,
+ 0x09, 0x02, 0x3d, 0x63, 0x82, 0xcf, 0x00, 0x09,
+ 0x03, 0x15, 0x60, 0x8e, 0x80, 0x30, 0x00, 0x00,
+ 0x02, 0x28, 0x47, 0x85, 0xb8, 0x00, 0x01, 0x04,
+ 0x11, 0x33, 0x8d, 0x8c, 0x80, 0x4a, 0x00, 0x01,
+ 0x02, 0x5d, 0x7a, 0x00, 0x00, 0x00, 0x02, 0x5d,
+ 0x7a, 0x84, 0x49, 0x00, 0x00, 0x04, 0x0b, 0x20,
0x2b, 0x3d, 0x00, 0x01, 0x20, 0x00, 0x04, 0x0b,
0x20, 0x2b, 0x3d, 0x00, 0x02, 0x20, 0x2b, 0x00,
0x01, 0x20, 0x01, 0x02, 0x0b, 0x20, 0x00, 0x02,
- 0x20, 0x7f, 0x00, 0x02, 0x0b, 0x20, 0x00, 0x02,
- 0x20, 0x7f, 0x00, 0x06, 0x20, 0x3d, 0x50, 0x72,
- 0x90, 0x92, 0x00, 0x01, 0x20, 0x01, 0x02, 0x20,
- 0x7f, 0x01, 0x01, 0x20, 0x00, 0x02, 0x20, 0x7f,
+ 0x20, 0x81, 0x00, 0x02, 0x0b, 0x20, 0x00, 0x02,
+ 0x20, 0x81, 0x00, 0x06, 0x20, 0x3d, 0x51, 0x74,
+ 0x92, 0x94, 0x00, 0x01, 0x20, 0x01, 0x02, 0x20,
+ 0x81, 0x01, 0x01, 0x20, 0x00, 0x02, 0x20, 0x81,
0x00, 0x02, 0x0b, 0x20, 0x06, 0x01, 0x20, 0x00,
- 0x02, 0x20, 0x61, 0x00, 0x02, 0x0b, 0x20, 0x01,
+ 0x02, 0x20, 0x63, 0x00, 0x02, 0x0b, 0x20, 0x01,
0x01, 0x20, 0x00, 0x02, 0x0b, 0x20, 0x03, 0x01,
- 0x20, 0x00, 0x08, 0x0b, 0x20, 0x2b, 0x3d, 0x61,
- 0x72, 0x92, 0x97, 0x00, 0x02, 0x20, 0x2b, 0x00,
+ 0x20, 0x00, 0x08, 0x0b, 0x20, 0x2b, 0x3d, 0x63,
+ 0x74, 0x94, 0x99, 0x00, 0x02, 0x20, 0x2b, 0x00,
0x03, 0x20, 0x2b, 0x3d, 0x01, 0x02, 0x0b, 0x20,
0x00, 0x01, 0x0b, 0x01, 0x02, 0x20, 0x2b, 0x00,
- 0x01, 0x61, 0x80, 0x44, 0x00, 0x01, 0x01, 0x2c,
- 0x35, 0x00, 0x00, 0x02, 0x1d, 0x89, 0x00, 0x00,
- 0x00, 0x01, 0x89, 0x81, 0xb3, 0x00, 0x00, 0x02,
- 0x46, 0x5c, 0x80, 0x3f, 0x00, 0x00, 0x03, 0x20,
- 0x2b, 0x46, 0x8c, 0xd1, 0x00, 0x00, 0x02, 0x1d,
+ 0x01, 0x63, 0x80, 0x44, 0x00, 0x01, 0x01, 0x2c,
+ 0x35, 0x00, 0x00, 0x02, 0x1d, 0x8b, 0x00, 0x00,
+ 0x00, 0x01, 0x8b, 0x81, 0xb3, 0x00, 0x00, 0x02,
+ 0x47, 0x5d, 0x80, 0x3f, 0x00, 0x00, 0x03, 0x20,
+ 0x2b, 0x47, 0x8c, 0xd1, 0x00, 0x00, 0x02, 0x1d,
0x29, 0x81, 0x3c, 0x00, 0x01, 0x06, 0x0d, 0x31,
- 0x30, 0x36, 0x3e, 0xa0, 0x00, 0x05, 0x0d, 0x31,
+ 0x30, 0x36, 0x3e, 0xa2, 0x00, 0x05, 0x0d, 0x31,
0x30, 0x36, 0x3e, 0x01, 0x00, 0x00, 0x01, 0x30,
0x00, 0x00, 0x09, 0x06, 0x0d, 0x31, 0x30, 0x36,
- 0x3e, 0xa0, 0x00, 0x00, 0x00, 0x05, 0x0d, 0x31,
+ 0x3e, 0xa2, 0x00, 0x00, 0x00, 0x05, 0x0d, 0x31,
0x30, 0x36, 0x3e, 0x07, 0x06, 0x0d, 0x31, 0x30,
- 0x36, 0x3e, 0xa0, 0x03, 0x05, 0x0d, 0x31, 0x30,
+ 0x36, 0x3e, 0xa2, 0x03, 0x05, 0x0d, 0x31, 0x30,
0x36, 0x3e, 0x09, 0x00, 0x03, 0x02, 0x0d, 0x30,
0x01, 0x00, 0x00, 0x05, 0x0d, 0x31, 0x30, 0x36,
0x3e, 0x04, 0x02, 0x36, 0x3e, 0x00, 0x00, 0x00,
@@ -3542,7 +3647,7 @@ static const uint8_t unicode_script_ext_table[828] = {
0x01, 0x03, 0x30, 0x36, 0x3e, 0x01, 0x01, 0x30,
0x58, 0x00, 0x03, 0x02, 0x36, 0x3e, 0x02, 0x00,
0x00, 0x02, 0x36, 0x3e, 0x59, 0x00, 0x00, 0x06,
- 0x0d, 0x31, 0x30, 0x36, 0x3e, 0xa0, 0x00, 0x02,
+ 0x0d, 0x31, 0x30, 0x36, 0x3e, 0xa2, 0x00, 0x02,
0x36, 0x3e, 0x80, 0x12, 0x00, 0x0f, 0x01, 0x30,
0x1f, 0x00, 0x23, 0x01, 0x30, 0x3b, 0x00, 0x27,
0x01, 0x30, 0x37, 0x00, 0x30, 0x01, 0x30, 0x0e,
@@ -3550,32 +3655,32 @@ static const uint8_t unicode_script_ext_table[828] = {
0x30, 0x57, 0x00, 0x18, 0x01, 0x30, 0x09, 0x00,
0x04, 0x01, 0x30, 0x5f, 0x00, 0x1e, 0x01, 0x30,
0xc0, 0x31, 0xef, 0x00, 0x00, 0x02, 0x1d, 0x29,
- 0x80, 0x0f, 0x00, 0x07, 0x02, 0x30, 0x46, 0x80,
+ 0x80, 0x0f, 0x00, 0x07, 0x02, 0x30, 0x47, 0x80,
0xa7, 0x00, 0x02, 0x0e, 0x20, 0x22, 0x2d, 0x2f,
- 0x42, 0x3d, 0x3c, 0x4f, 0x50, 0x5b, 0x61, 0x44,
- 0x8f, 0x97, 0x02, 0x0d, 0x20, 0x22, 0x2d, 0x2f,
- 0x42, 0x3d, 0x3c, 0x4f, 0x5b, 0x61, 0x44, 0x8f,
- 0x97, 0x03, 0x0b, 0x20, 0x22, 0x2d, 0x2f, 0x42,
- 0x3c, 0x4f, 0x5b, 0x44, 0x8f, 0x97, 0x80, 0x36,
+ 0x43, 0x3d, 0x3c, 0x50, 0x51, 0x5c, 0x63, 0x45,
+ 0x91, 0x99, 0x02, 0x0d, 0x20, 0x22, 0x2d, 0x2f,
+ 0x43, 0x3d, 0x3c, 0x50, 0x5c, 0x63, 0x45, 0x91,
+ 0x99, 0x03, 0x0b, 0x20, 0x22, 0x2d, 0x2f, 0x43,
+ 0x3c, 0x50, 0x5c, 0x45, 0x91, 0x99, 0x80, 0x36,
0x00, 0x00, 0x02, 0x0b, 0x20, 0x00, 0x00, 0x00,
- 0x02, 0x20, 0x90, 0x39, 0x00, 0x00, 0x03, 0x3f,
- 0x46, 0x5f, 0x80, 0x1f, 0x00, 0x00, 0x02, 0x10,
+ 0x02, 0x20, 0x92, 0x39, 0x00, 0x00, 0x03, 0x40,
+ 0x47, 0x60, 0x80, 0x1f, 0x00, 0x00, 0x02, 0x10,
0x3b, 0xc0, 0x12, 0xed, 0x00, 0x01, 0x02, 0x04,
- 0x64, 0x80, 0x31, 0x00, 0x00, 0x02, 0x04, 0x93,
- 0x09, 0x00, 0x00, 0x02, 0x04, 0x93, 0x46, 0x00,
+ 0x66, 0x80, 0x31, 0x00, 0x00, 0x02, 0x04, 0x95,
+ 0x09, 0x00, 0x00, 0x02, 0x04, 0x95, 0x46, 0x00,
0x01, 0x05, 0x0d, 0x31, 0x30, 0x36, 0x3e, 0x80,
0x99, 0x00, 0x04, 0x06, 0x0d, 0x31, 0x30, 0x36,
- 0x3e, 0xa0, 0x09, 0x00, 0x00, 0x02, 0x36, 0x3e,
+ 0x3e, 0xa2, 0x09, 0x00, 0x00, 0x02, 0x36, 0x3e,
0x2c, 0x00, 0x01, 0x02, 0x36, 0x3e, 0x80, 0xdf,
- 0x00, 0x01, 0x03, 0x1e, 0x1c, 0x4a, 0x00, 0x02,
- 0x1c, 0x4a, 0x03, 0x00, 0x2c, 0x03, 0x1c, 0x49,
- 0x4a, 0x02, 0x00, 0x08, 0x02, 0x1c, 0x4a, 0x81,
+ 0x00, 0x01, 0x03, 0x1e, 0x1c, 0x4b, 0x00, 0x02,
+ 0x1c, 0x4b, 0x03, 0x00, 0x2c, 0x03, 0x1c, 0x4a,
+ 0x4b, 0x02, 0x00, 0x08, 0x02, 0x1c, 0x4b, 0x81,
0x1f, 0x00, 0x1b, 0x02, 0x04, 0x1a, 0x87, 0x75,
- 0x00, 0x00, 0x02, 0x52, 0x71, 0x87, 0x8d, 0x00,
- 0x00, 0x02, 0x2b, 0x90, 0x00, 0x00, 0x00, 0x02,
- 0x2b, 0x90, 0x36, 0x00, 0x01, 0x02, 0x2b, 0x90,
- 0x8c, 0x12, 0x00, 0x01, 0x02, 0x2b, 0x90, 0x00,
- 0x00, 0x00, 0x02, 0x2b, 0x90, 0xc0, 0x5c, 0x4b,
+ 0x00, 0x00, 0x02, 0x53, 0x73, 0x87, 0x8d, 0x00,
+ 0x00, 0x02, 0x2b, 0x92, 0x00, 0x00, 0x00, 0x02,
+ 0x2b, 0x92, 0x36, 0x00, 0x01, 0x02, 0x2b, 0x92,
+ 0x8c, 0x12, 0x00, 0x01, 0x02, 0x2b, 0x92, 0x00,
+ 0x00, 0x00, 0x02, 0x2b, 0x92, 0xc0, 0x5c, 0x4b,
0x00, 0x03, 0x01, 0x23, 0x96, 0x3b, 0x00, 0x11,
0x01, 0x30, 0x9e, 0x5d, 0x00, 0x01, 0x01, 0x30,
0xce, 0xcd, 0x2d, 0x00,
@@ -3616,7 +3721,7 @@ static const uint8_t unicode_prop_Other_Math_table[200] = {
0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90,
};
-static const uint8_t unicode_prop_Other_Alphabetic_table[417] = {
+static const uint8_t unicode_prop_Other_Alphabetic_table[428] = {
0x43, 0x44, 0x80, 0x42, 0x69, 0x8d, 0x00, 0x01,
0x01, 0x00, 0xc7, 0x8a, 0xaf, 0x8c, 0x06, 0x8f,
0x80, 0xe4, 0x33, 0x19, 0x0b, 0x80, 0xa2, 0x80,
@@ -3628,59 +3733,61 @@ static const uint8_t unicode_prop_Other_Alphabetic_table[417] = {
0x0a, 0x80, 0x8a, 0x82, 0xb9, 0x38, 0x10, 0x81,
0x94, 0x81, 0x95, 0x13, 0x82, 0xb9, 0x31, 0x09,
0x81, 0x88, 0x81, 0x89, 0x81, 0x9d, 0x80, 0xba,
- 0x22, 0x10, 0x82, 0x89, 0x80, 0xa7, 0x83, 0xb9,
+ 0x22, 0x10, 0x82, 0x89, 0x80, 0xa7, 0x84, 0xb8,
0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x9c, 0x82,
- 0xb9, 0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x9b,
- 0x83, 0xb9, 0x30, 0x10, 0x82, 0x89, 0x80, 0x89,
- 0x81, 0x9c, 0x82, 0xca, 0x28, 0x00, 0x87, 0x91,
- 0x81, 0xbc, 0x01, 0x86, 0x91, 0x80, 0xe2, 0x01,
- 0x28, 0x81, 0x8f, 0x80, 0x40, 0xa2, 0x90, 0x8a,
- 0x8a, 0x80, 0xa3, 0xed, 0x8b, 0x00, 0x0b, 0x96,
- 0x1b, 0x10, 0x11, 0x32, 0x83, 0x8c, 0x8b, 0x00,
- 0x89, 0x83, 0x46, 0x73, 0x81, 0x9d, 0x81, 0x9d,
- 0x81, 0x9d, 0x81, 0xc1, 0x92, 0x40, 0xbb, 0x81,
- 0xa1, 0x80, 0xf5, 0x8b, 0x83, 0x88, 0x40, 0xdd,
- 0x84, 0xb8, 0x89, 0x81, 0x93, 0xc9, 0x81, 0x8a,
- 0x82, 0xb0, 0x84, 0xaf, 0x8e, 0xbb, 0x82, 0x9d,
- 0x88, 0x09, 0xb8, 0x8a, 0xb1, 0x92, 0x41, 0xaf,
- 0x8d, 0x46, 0xc0, 0xb3, 0x48, 0xf5, 0x9f, 0x60,
- 0x78, 0x73, 0x87, 0xa1, 0x81, 0x41, 0x61, 0x07,
- 0x80, 0x96, 0x84, 0xd7, 0x81, 0xb1, 0x8f, 0x00,
- 0xb8, 0x80, 0xa5, 0x84, 0x9b, 0x8b, 0xac, 0x83,
- 0xaf, 0x8b, 0xa4, 0x80, 0xc2, 0x8d, 0x8b, 0x07,
- 0x81, 0xac, 0x82, 0xb1, 0x00, 0x11, 0x0c, 0x80,
- 0xab, 0x24, 0x80, 0x40, 0xec, 0x87, 0x60, 0x4f,
- 0x32, 0x80, 0x48, 0x56, 0x84, 0x46, 0x85, 0x10,
- 0x0c, 0x83, 0x43, 0x13, 0x83, 0x41, 0x82, 0x81,
- 0x41, 0x52, 0x82, 0xb4, 0x8d, 0xac, 0x81, 0x8c,
- 0x80, 0xac, 0x88, 0x88, 0x80, 0xbc, 0x82, 0xa3,
- 0x8b, 0x91, 0x81, 0xb8, 0x82, 0xaf, 0x8c, 0x8d,
- 0x81, 0xdb, 0x88, 0x08, 0x28, 0x40, 0x9f, 0x89,
- 0x96, 0x83, 0xb9, 0x31, 0x09, 0x81, 0x89, 0x80,
- 0x89, 0x81, 0x40, 0xd0, 0x8c, 0x02, 0xe9, 0x91,
- 0x40, 0xec, 0x31, 0x86, 0x9c, 0x81, 0xd1, 0x8e,
- 0x00, 0xe9, 0x8a, 0xe6, 0x8d, 0x41, 0x00, 0x8c,
- 0x40, 0xf6, 0x28, 0x09, 0x0a, 0x00, 0x80, 0x40,
- 0x8d, 0x31, 0x2b, 0x80, 0x9b, 0x89, 0xa9, 0x20,
- 0x83, 0x91, 0x8a, 0xad, 0x8d, 0x41, 0x96, 0x38,
- 0x86, 0xd2, 0x95, 0x80, 0x8d, 0xf9, 0x2a, 0x00,
- 0x08, 0x10, 0x02, 0x80, 0xc1, 0x20, 0x08, 0x83,
- 0x41, 0x5b, 0x83, 0x60, 0x50, 0x57, 0x00, 0xb6,
- 0x33, 0xdc, 0x81, 0x60, 0x4c, 0xab, 0x80, 0x60,
- 0x23, 0x60, 0x30, 0x90, 0x0e, 0x01, 0x04, 0x49,
- 0x1b, 0x80, 0x47, 0xe7, 0x99, 0x85, 0x99, 0x85,
- 0x99,
+ 0xb9, 0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x8e,
+ 0x80, 0x8b, 0x83, 0xb9, 0x30, 0x10, 0x82, 0x89,
+ 0x80, 0x89, 0x81, 0x9c, 0x82, 0xca, 0x28, 0x00,
+ 0x87, 0x91, 0x81, 0xbc, 0x01, 0x86, 0x91, 0x80,
+ 0xe2, 0x01, 0x28, 0x81, 0x8f, 0x80, 0x40, 0xa2,
+ 0x92, 0x88, 0x8a, 0x80, 0xa3, 0xed, 0x8b, 0x00,
+ 0x0b, 0x96, 0x1b, 0x10, 0x11, 0x32, 0x83, 0x8c,
+ 0x8b, 0x00, 0x89, 0x83, 0x46, 0x73, 0x81, 0x9d,
+ 0x81, 0x9d, 0x81, 0x9d, 0x81, 0xc1, 0x92, 0x40,
+ 0xbb, 0x81, 0xa1, 0x80, 0xf5, 0x8b, 0x83, 0x88,
+ 0x40, 0xdd, 0x84, 0xb8, 0x89, 0x81, 0x93, 0xc9,
+ 0x81, 0x8a, 0x82, 0xb0, 0x84, 0xaf, 0x8e, 0xbb,
+ 0x82, 0x9d, 0x88, 0x09, 0xb8, 0x8a, 0xb1, 0x92,
+ 0x41, 0xaf, 0x8d, 0x46, 0xc0, 0xb3, 0x48, 0xf5,
+ 0x9f, 0x60, 0x78, 0x73, 0x87, 0xa1, 0x81, 0x41,
+ 0x61, 0x07, 0x80, 0x96, 0x84, 0xd7, 0x81, 0xb1,
+ 0x8f, 0x00, 0xb8, 0x80, 0xa5, 0x84, 0x9b, 0x8b,
+ 0xac, 0x83, 0xaf, 0x8b, 0xa4, 0x80, 0xc2, 0x8d,
+ 0x8b, 0x07, 0x81, 0xac, 0x82, 0xb1, 0x00, 0x11,
+ 0x0c, 0x80, 0xab, 0x24, 0x80, 0x40, 0xec, 0x87,
+ 0x60, 0x4f, 0x32, 0x80, 0x48, 0x56, 0x84, 0x46,
+ 0x85, 0x10, 0x0c, 0x83, 0x43, 0x13, 0x83, 0x41,
+ 0x82, 0x81, 0x41, 0x52, 0x82, 0xb4, 0x8d, 0xac,
+ 0x81, 0x8a, 0x82, 0xac, 0x88, 0x88, 0x80, 0xbc,
+ 0x82, 0xa3, 0x8b, 0x91, 0x81, 0xb8, 0x82, 0xaf,
+ 0x8c, 0x8d, 0x81, 0xdb, 0x88, 0x08, 0x28, 0x08,
+ 0x40, 0x9c, 0x89, 0x96, 0x83, 0xb9, 0x31, 0x09,
+ 0x81, 0x89, 0x80, 0x89, 0x81, 0x40, 0xd0, 0x8c,
+ 0x02, 0xe9, 0x91, 0x40, 0xec, 0x31, 0x86, 0x9c,
+ 0x81, 0xd1, 0x8e, 0x00, 0xe9, 0x8a, 0xe6, 0x8d,
+ 0x41, 0x00, 0x8c, 0x40, 0xf6, 0x28, 0x09, 0x0a,
+ 0x00, 0x80, 0x40, 0x8d, 0x31, 0x2b, 0x80, 0x9b,
+ 0x89, 0xa9, 0x20, 0x83, 0x91, 0x8a, 0xad, 0x8d,
+ 0x41, 0x96, 0x38, 0x86, 0xd2, 0x95, 0x80, 0x8d,
+ 0xf9, 0x2a, 0x00, 0x08, 0x10, 0x02, 0x80, 0xc1,
+ 0x20, 0x08, 0x83, 0x41, 0x5b, 0x83, 0x88, 0x08,
+ 0x80, 0xaf, 0x32, 0x82, 0x60, 0x50, 0x0d, 0x00,
+ 0xb6, 0x33, 0xdc, 0x81, 0x60, 0x4c, 0xab, 0x80,
+ 0x60, 0x23, 0x60, 0x30, 0x90, 0x0e, 0x01, 0x04,
+ 0xe3, 0x80, 0x48, 0xb6, 0x80, 0x47, 0xe7, 0x99,
+ 0x85, 0x99, 0x85, 0x99,
};
-static const uint8_t unicode_prop_Other_Lowercase_table[59] = {
+static const uint8_t unicode_prop_Other_Lowercase_table[69] = {
0x40, 0xa9, 0x80, 0x8e, 0x80, 0x41, 0xf4, 0x88,
- 0x31, 0x9d, 0x84, 0xdf, 0x80, 0xb3, 0x80, 0x59,
- 0xb0, 0xbe, 0x8c, 0x80, 0xa1, 0xa4, 0x42, 0xb0,
- 0x80, 0x8c, 0x80, 0x8f, 0x8c, 0x40, 0xd2, 0x8f,
- 0x43, 0x4f, 0x99, 0x47, 0x91, 0x81, 0x60, 0x7a,
- 0x1d, 0x81, 0x40, 0xd1, 0x80, 0x40, 0x86, 0x81,
- 0x43, 0x61, 0x83, 0x60, 0x5c, 0x1f, 0x01, 0x10,
- 0xa9, 0x80, 0x88,
+ 0x31, 0x9d, 0x84, 0xdf, 0x80, 0xb3, 0x80, 0x4d,
+ 0x80, 0x80, 0x4c, 0x2e, 0xbe, 0x8c, 0x80, 0xa1,
+ 0xa4, 0x42, 0xb0, 0x80, 0x8c, 0x80, 0x8f, 0x8c,
+ 0x40, 0xd2, 0x8f, 0x43, 0x4f, 0x99, 0x47, 0x91,
+ 0x81, 0x60, 0x7a, 0x1d, 0x81, 0x40, 0xd1, 0x80,
+ 0x40, 0x80, 0x12, 0x81, 0x43, 0x61, 0x83, 0x88,
+ 0x80, 0x60, 0x5c, 0x15, 0x01, 0x10, 0xa9, 0x80,
+ 0x88, 0x60, 0xd8, 0x74, 0xbd,
};
static const uint8_t unicode_prop_Other_Uppercase_table[15] = {
@@ -3742,71 +3849,70 @@ static const uint8_t unicode_prop_Changes_When_Titlecased1_table[22] = {
0x8b, 0x80, 0x8e, 0x80, 0xae, 0x80,
};
-static const uint8_t unicode_prop_Changes_When_Casefolded1_table[33] = {
- 0x40, 0xde, 0x80, 0xcf, 0x80, 0x97, 0x80, 0x44,
- 0x3c, 0x80, 0x59, 0x11, 0x80, 0x40, 0xe4, 0x3f,
- 0x3f, 0x87, 0x89, 0x11, 0x05, 0x02, 0x11, 0x80,
- 0xa9, 0x11, 0x80, 0x60, 0xdb, 0x07, 0x86, 0x8b,
- 0x84,
+static const uint8_t unicode_prop_Changes_When_Casefolded1_table[29] = {
+ 0x41, 0xef, 0x80, 0x41, 0x9e, 0x80, 0x9e, 0x80,
+ 0x5a, 0xe4, 0x83, 0x40, 0xb5, 0x00, 0x00, 0x00,
+ 0x80, 0xde, 0x06, 0x06, 0x80, 0x8a, 0x09, 0x81,
+ 0x89, 0x10, 0x81, 0x8d, 0x80,
};
-static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[448] = {
+static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[447] = {
0x40, 0x9f, 0x06, 0x00, 0x01, 0x00, 0x01, 0x12,
- 0x10, 0x82, 0x9f, 0x80, 0xcf, 0x01, 0x80, 0x8b,
- 0x07, 0x80, 0xfb, 0x01, 0x01, 0x80, 0xa5, 0x80,
- 0x40, 0xbb, 0x88, 0x9e, 0x29, 0x84, 0xda, 0x08,
- 0x81, 0x89, 0x80, 0xa3, 0x04, 0x02, 0x04, 0x08,
- 0x80, 0xc9, 0x82, 0x9c, 0x80, 0x41, 0x93, 0x80,
- 0x40, 0x93, 0x80, 0xd7, 0x83, 0x42, 0xde, 0x87,
- 0xfb, 0x08, 0x80, 0xd2, 0x01, 0x80, 0xa1, 0x11,
- 0x80, 0x40, 0xfc, 0x81, 0x42, 0xd4, 0x80, 0xfe,
- 0x80, 0xa7, 0x81, 0xad, 0x80, 0xb5, 0x80, 0x88,
- 0x03, 0x03, 0x03, 0x80, 0x8b, 0x80, 0x88, 0x00,
- 0x26, 0x80, 0x90, 0x80, 0x88, 0x03, 0x03, 0x03,
- 0x80, 0x8b, 0x80, 0x41, 0x41, 0x80, 0xe1, 0x81,
- 0x46, 0x52, 0x81, 0xd4, 0x84, 0x45, 0x1b, 0x10,
- 0x8a, 0x80, 0x91, 0x80, 0x9b, 0x8c, 0x80, 0xa1,
- 0xa4, 0x40, 0xd9, 0x80, 0x40, 0xd5, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x3f, 0x3f, 0x87,
- 0x89, 0x11, 0x04, 0x00, 0x29, 0x04, 0x12, 0x80,
- 0x88, 0x12, 0x80, 0x88, 0x11, 0x11, 0x04, 0x08,
- 0x8f, 0x00, 0x20, 0x8b, 0x12, 0x2a, 0x08, 0x0b,
- 0x00, 0x07, 0x82, 0x8c, 0x06, 0x92, 0x81, 0x9a,
- 0x80, 0x8c, 0x8a, 0x80, 0xd6, 0x18, 0x10, 0x8a,
- 0x01, 0x0c, 0x0a, 0x00, 0x10, 0x11, 0x02, 0x06,
- 0x05, 0x1c, 0x85, 0x8f, 0x8f, 0x8f, 0x88, 0x80,
- 0x40, 0xa1, 0x08, 0x81, 0x40, 0xf7, 0x81, 0x41,
- 0x34, 0xd5, 0x99, 0x9a, 0x45, 0x20, 0x80, 0xe6,
- 0x82, 0xe4, 0x80, 0x41, 0x9e, 0x81, 0x40, 0xf0,
- 0x80, 0x41, 0x2e, 0x80, 0xd2, 0x80, 0x8b, 0x40,
- 0xd5, 0xa9, 0x80, 0xb4, 0x00, 0x82, 0xdf, 0x09,
- 0x80, 0xde, 0x80, 0xb0, 0xdd, 0x82, 0x8d, 0xdf,
- 0x9e, 0x80, 0xa7, 0x87, 0xae, 0x80, 0x41, 0x7f,
- 0x60, 0x72, 0x9b, 0x81, 0x40, 0xd1, 0x80, 0x40,
- 0x80, 0x12, 0x81, 0x43, 0x61, 0x83, 0x88, 0x80,
- 0x60, 0x4d, 0x95, 0x41, 0x0d, 0x08, 0x00, 0x81,
- 0x89, 0x00, 0x00, 0x09, 0x82, 0xc3, 0x81, 0xe9,
- 0xa5, 0x86, 0x8b, 0x24, 0x00, 0x97, 0x04, 0x00,
- 0x01, 0x01, 0x80, 0xeb, 0xa0, 0x41, 0x6a, 0x91,
- 0xbf, 0x81, 0xb5, 0xa7, 0x8c, 0x82, 0x99, 0x95,
- 0x94, 0x81, 0x8b, 0x80, 0x92, 0x03, 0x1a, 0x00,
- 0x80, 0x40, 0x86, 0x08, 0x80, 0x9f, 0x99, 0x40,
- 0x83, 0x15, 0x0d, 0x0d, 0x0a, 0x16, 0x06, 0x80,
- 0x88, 0x47, 0x87, 0x20, 0xa9, 0x80, 0x88, 0x60,
- 0xb4, 0xe4, 0x83, 0x54, 0xb9, 0x86, 0x8d, 0x87,
- 0xbf, 0x85, 0x42, 0x3e, 0xd4, 0x80, 0xc6, 0x01,
- 0x08, 0x09, 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80,
- 0xc0, 0x03, 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04,
- 0x00, 0x16, 0x80, 0x41, 0x53, 0x81, 0x41, 0x23,
- 0x81, 0xb1, 0x55, 0xff, 0x18, 0x9a, 0x01, 0x00,
- 0x08, 0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18,
- 0x00, 0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03,
- 0x00, 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80,
- 0x90, 0x42, 0x43, 0x8a, 0x84, 0x9e, 0x80, 0x9f,
- 0x99, 0x82, 0xa2, 0x80, 0xee, 0x82, 0x8c, 0xab,
- 0x83, 0x88, 0x31, 0x49, 0x9d, 0x89, 0x60, 0xfc,
- 0x05, 0x42, 0x1d, 0x6b, 0x05, 0xe1, 0x4f, 0xff,
+ 0x10, 0x82, 0xf3, 0x80, 0x8b, 0x80, 0x40, 0x84,
+ 0x01, 0x01, 0x80, 0xa2, 0x01, 0x80, 0x40, 0xbb,
+ 0x88, 0x9e, 0x29, 0x84, 0xda, 0x08, 0x81, 0x89,
+ 0x80, 0xa3, 0x04, 0x02, 0x04, 0x08, 0x07, 0x80,
+ 0x9e, 0x80, 0xa0, 0x82, 0x9c, 0x80, 0x42, 0x28,
+ 0x80, 0xd7, 0x83, 0x42, 0xde, 0x87, 0xfb, 0x08,
+ 0x80, 0xd2, 0x01, 0x80, 0xa1, 0x11, 0x80, 0x40,
+ 0xfc, 0x81, 0x42, 0xd4, 0x80, 0xfe, 0x80, 0xa7,
+ 0x81, 0xad, 0x80, 0xb5, 0x80, 0x88, 0x03, 0x03,
+ 0x03, 0x80, 0x8b, 0x80, 0x88, 0x00, 0x26, 0x80,
+ 0x90, 0x80, 0x88, 0x03, 0x03, 0x03, 0x80, 0x8b,
+ 0x80, 0x41, 0x41, 0x80, 0xe1, 0x81, 0x46, 0x52,
+ 0x81, 0xd4, 0x84, 0x45, 0x1b, 0x10, 0x8a, 0x80,
+ 0x91, 0x80, 0x9b, 0x8c, 0x80, 0xa1, 0xa4, 0x40,
+ 0xd5, 0x83, 0x40, 0xb5, 0x00, 0x00, 0x00, 0x80,
+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0xb7, 0x05, 0x00, 0x13, 0x05, 0x11, 0x02, 0x0c,
+ 0x11, 0x00, 0x00, 0x0c, 0x15, 0x05, 0x08, 0x8f,
+ 0x00, 0x20, 0x8b, 0x12, 0x2a, 0x08, 0x0b, 0x00,
+ 0x07, 0x82, 0x8c, 0x06, 0x92, 0x81, 0x9a, 0x80,
+ 0x8c, 0x8a, 0x80, 0xd6, 0x18, 0x10, 0x8a, 0x01,
+ 0x0c, 0x0a, 0x00, 0x10, 0x11, 0x02, 0x06, 0x05,
+ 0x1c, 0x85, 0x8f, 0x8f, 0x8f, 0x88, 0x80, 0x40,
+ 0xa1, 0x08, 0x81, 0x40, 0xf7, 0x81, 0x41, 0x34,
+ 0xd5, 0x99, 0x9a, 0x45, 0x20, 0x80, 0xe6, 0x82,
+ 0xe4, 0x80, 0x41, 0x9e, 0x81, 0x40, 0xf0, 0x80,
+ 0x41, 0x2e, 0x80, 0xd2, 0x80, 0x8b, 0x40, 0xd5,
+ 0xa9, 0x80, 0xb4, 0x00, 0x82, 0xdf, 0x09, 0x80,
+ 0xde, 0x80, 0xb0, 0xdd, 0x82, 0x8d, 0xdf, 0x9e,
+ 0x80, 0xa7, 0x87, 0xae, 0x80, 0x41, 0x7f, 0x60,
+ 0x72, 0x9b, 0x81, 0x40, 0xd1, 0x80, 0x40, 0x80,
+ 0x12, 0x81, 0x43, 0x61, 0x83, 0x88, 0x80, 0x60,
+ 0x4d, 0x95, 0x41, 0x0d, 0x08, 0x00, 0x81, 0x89,
+ 0x00, 0x00, 0x09, 0x82, 0xc3, 0x81, 0xe9, 0xc2,
+ 0x00, 0x97, 0x04, 0x00, 0x01, 0x01, 0x80, 0xeb,
+ 0xa0, 0x41, 0x6a, 0x91, 0xbf, 0x81, 0xb5, 0xa7,
+ 0x8c, 0x82, 0x99, 0x95, 0x94, 0x81, 0x8b, 0x80,
+ 0x92, 0x03, 0x1a, 0x00, 0x80, 0x40, 0x86, 0x08,
+ 0x80, 0x9f, 0x99, 0x40, 0x83, 0x15, 0x0d, 0x0d,
+ 0x0a, 0x16, 0x06, 0x80, 0x88, 0x47, 0x87, 0x20,
+ 0xa9, 0x80, 0x88, 0x60, 0xb4, 0xe4, 0x83, 0x54,
+ 0xb9, 0x86, 0x8d, 0x87, 0xbf, 0x85, 0x42, 0x3e,
+ 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80,
+ 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06,
+ 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80, 0x41,
+ 0x53, 0x81, 0x41, 0x23, 0x81, 0xb1, 0x48, 0x2f,
+ 0xbd, 0x4d, 0x91, 0x18, 0x9a, 0x01, 0x00, 0x08,
+ 0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18, 0x00,
+ 0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00,
+ 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90,
+ 0x42, 0x43, 0x8a, 0x84, 0x9e, 0x80, 0x9f, 0x99,
+ 0x82, 0xa2, 0x80, 0xee, 0x82, 0x8c, 0xab, 0x83,
+ 0x88, 0x31, 0x49, 0x9d, 0x89, 0x60, 0xfc, 0x05,
+ 0x42, 0x1d, 0x6b, 0x05, 0xe1, 0x4f, 0xff,
};
static const uint8_t unicode_prop_ASCII_Hex_Digit_table[5] = {
@@ -3834,7 +3940,7 @@ static const uint8_t unicode_prop_Deprecated_table[23] = {
0x42, 0xb8, 0x81, 0x6d, 0xdc, 0xd5, 0x80,
};
-static const uint8_t unicode_prop_Diacritic_table[391] = {
+static const uint8_t unicode_prop_Diacritic_table[399] = {
0xdd, 0x00, 0x80, 0xc6, 0x05, 0x03, 0x01, 0x81,
0x41, 0xf6, 0x40, 0x9e, 0x07, 0x25, 0x90, 0x0b,
0x80, 0x88, 0x81, 0x40, 0xfc, 0x84, 0x40, 0xd0,
@@ -3869,20 +3975,21 @@ static const uint8_t unicode_prop_Diacritic_table[391] = {
0x00, 0x8f, 0x41, 0x0d, 0x00, 0x80, 0xae, 0x80,
0xac, 0x81, 0xc2, 0x80, 0x42, 0xfb, 0x80, 0x44,
0x9e, 0x28, 0xa9, 0x80, 0x88, 0x43, 0x29, 0x81,
- 0x42, 0x3a, 0x85, 0x42, 0x1d, 0x8a, 0xb0, 0x83,
- 0x40, 0xbf, 0x80, 0xa8, 0x80, 0xc7, 0x81, 0xf7,
- 0x81, 0xbd, 0x80, 0xcb, 0x80, 0x88, 0x82, 0xe7,
- 0x81, 0x40, 0xb1, 0x81, 0xd0, 0x80, 0x8f, 0x80,
- 0x97, 0x32, 0x84, 0x40, 0xcc, 0x02, 0x80, 0xfa,
- 0x81, 0x40, 0xfa, 0x81, 0xfd, 0x80, 0xf5, 0x81,
- 0xf2, 0x80, 0x41, 0x0c, 0x81, 0x41, 0x01, 0x0b,
- 0x80, 0x40, 0x9b, 0x80, 0xd2, 0x80, 0x91, 0x80,
- 0xd0, 0x80, 0x41, 0xa4, 0x80, 0x41, 0x01, 0x00,
- 0x81, 0xd0, 0x80, 0x60, 0x4d, 0x57, 0x84, 0xba,
- 0x86, 0x44, 0x57, 0x90, 0xcf, 0x81, 0x60, 0x3f,
- 0xfd, 0x18, 0x30, 0x81, 0x5f, 0x00, 0xad, 0x81,
- 0x96, 0x42, 0x1f, 0x12, 0x2f, 0x39, 0x86, 0x9d,
- 0x83, 0x4f, 0x81, 0x86, 0x41, 0x76, 0x80, 0xbc,
+ 0x42, 0x3a, 0x85, 0x41, 0xd4, 0x82, 0xc5, 0x8a,
+ 0xb0, 0x83, 0x40, 0xbf, 0x80, 0xa8, 0x80, 0xc7,
+ 0x81, 0xf7, 0x81, 0xbd, 0x80, 0xcb, 0x80, 0x88,
+ 0x82, 0xe7, 0x81, 0x40, 0xb1, 0x81, 0xd0, 0x80,
+ 0x8f, 0x80, 0x97, 0x32, 0x84, 0x40, 0xcc, 0x02,
+ 0x80, 0xfa, 0x81, 0x40, 0xfa, 0x81, 0xfd, 0x80,
+ 0xf5, 0x81, 0xf2, 0x80, 0x41, 0x0c, 0x81, 0x41,
+ 0x01, 0x0b, 0x80, 0x40, 0x9b, 0x80, 0xd2, 0x80,
+ 0x91, 0x80, 0xd0, 0x80, 0x41, 0xa4, 0x80, 0x41,
+ 0x01, 0x00, 0x81, 0xd0, 0x80, 0x56, 0xae, 0x8e,
+ 0x60, 0x36, 0x99, 0x84, 0xba, 0x86, 0x44, 0x57,
+ 0x90, 0xcf, 0x81, 0x60, 0x3f, 0xfd, 0x18, 0x30,
+ 0x81, 0x5f, 0x00, 0xad, 0x81, 0x96, 0x42, 0x1f,
+ 0x12, 0x2f, 0x39, 0x86, 0x9d, 0x83, 0x4e, 0x81,
+ 0xbd, 0x40, 0xc1, 0x86, 0x41, 0x76, 0x80, 0xbc,
0x83, 0x45, 0xdf, 0x86, 0xec, 0x10, 0x82,
};
@@ -3914,16 +4021,16 @@ static const uint8_t unicode_prop_IDS_Trinary_Operator_table[4] = {
0x60, 0x2f, 0xf1, 0x81,
};
-static const uint8_t unicode_prop_Ideographic_table[66] = {
+static const uint8_t unicode_prop_Ideographic_table[69] = {
0x60, 0x30, 0x05, 0x81, 0x98, 0x88, 0x8d, 0x82,
0x43, 0xc4, 0x59, 0xbf, 0xbf, 0x60, 0x51, 0xff,
0x60, 0x58, 0xff, 0x41, 0x6d, 0x81, 0xe9, 0x60,
0x75, 0x09, 0x80, 0x9a, 0x57, 0xf7, 0x87, 0x44,
0xd5, 0xa9, 0x88, 0x60, 0x24, 0x66, 0x41, 0x8b,
0x60, 0x4d, 0x03, 0x60, 0xa6, 0xdf, 0x9f, 0x50,
- 0x38, 0x86, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d,
+ 0x39, 0x85, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d,
0x5d, 0x30, 0x4c, 0x1e, 0x42, 0x1d, 0x45, 0xe1,
- 0x53, 0x4a,
+ 0x53, 0x4a, 0x84, 0x50, 0x5f,
};
static const uint8_t unicode_prop_Join_Control_table[4] = {
@@ -3979,7 +4086,7 @@ static const uint8_t unicode_prop_Regional_Indicator_table[4] = {
0x61, 0xf1, 0xe5, 0x99,
};
-static const uint8_t unicode_prop_Sentence_Terminal_table[194] = {
+static const uint8_t unicode_prop_Sentence_Terminal_table[196] = {
0xa0, 0x80, 0x8b, 0x80, 0x8f, 0x80, 0x45, 0x48,
0x80, 0x40, 0x92, 0x82, 0x40, 0xb3, 0x80, 0xaa,
0x82, 0x40, 0xf5, 0x80, 0xbc, 0x00, 0x02, 0x81,
@@ -4001,13 +4108,13 @@ static const uint8_t unicode_prop_Sentence_Terminal_table[194] = {
0xeb, 0x80, 0x41, 0xa0, 0x81, 0x41, 0x74, 0x0c,
0x8e, 0xe8, 0x81, 0x40, 0xf8, 0x82, 0x42, 0x04,
0x00, 0x80, 0x40, 0xfa, 0x81, 0xd6, 0x81, 0x41,
- 0xa3, 0x81, 0x42, 0xb3, 0x81, 0x60, 0x4b, 0x74,
- 0x81, 0x40, 0x84, 0x80, 0xc0, 0x81, 0x8a, 0x80,
- 0x43, 0x52, 0x80, 0x60, 0x4e, 0x05, 0x80, 0x5d,
- 0xe7, 0x80,
+ 0xa3, 0x81, 0x42, 0xb3, 0x81, 0xc9, 0x81, 0x60,
+ 0x4b, 0x28, 0x81, 0x40, 0x84, 0x80, 0xc0, 0x81,
+ 0x8a, 0x80, 0x43, 0x52, 0x80, 0x60, 0x4e, 0x05,
+ 0x80, 0x5d, 0xe7, 0x80,
};
-static const uint8_t unicode_prop_Soft_Dotted_table[74] = {
+static const uint8_t unicode_prop_Soft_Dotted_table[79] = {
0xe8, 0x81, 0x40, 0xc3, 0x80, 0x41, 0x18, 0x80,
0x9d, 0x80, 0xb3, 0x80, 0x93, 0x80, 0x41, 0x3f,
0x80, 0xe1, 0x00, 0x80, 0x59, 0x08, 0x80, 0xb2,
@@ -4017,10 +4124,10 @@ static const uint8_t unicode_prop_Soft_Dotted_table[74] = {
0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1,
0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1,
0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0x48,
- 0x85, 0x80,
+ 0x85, 0x80, 0x41, 0x30, 0x81, 0x99, 0x80,
};
-static const uint8_t unicode_prop_Terminal_Punctuation_table[246] = {
+static const uint8_t unicode_prop_Terminal_Punctuation_table[248] = {
0xa0, 0x80, 0x89, 0x00, 0x80, 0x8a, 0x0a, 0x80,
0x43, 0x3d, 0x07, 0x80, 0x42, 0x00, 0x80, 0xb8,
0x80, 0xc7, 0x80, 0x8d, 0x00, 0x82, 0x40, 0xb3,
@@ -4048,19 +4155,19 @@ static const uint8_t unicode_prop_Terminal_Punctuation_table[246] = {
0x82, 0x8b, 0x81, 0x41, 0x65, 0x1a, 0x8e, 0xe8,
0x81, 0x40, 0xf8, 0x82, 0x42, 0x04, 0x00, 0x80,
0x40, 0xfa, 0x81, 0xd6, 0x0b, 0x81, 0x41, 0x9d,
- 0x82, 0xac, 0x80, 0x42, 0x84, 0x81, 0x45, 0x76,
- 0x84, 0x60, 0x45, 0xf8, 0x81, 0x40, 0x84, 0x80,
- 0xc0, 0x82, 0x89, 0x80, 0x43, 0x51, 0x81, 0x60,
- 0x4e, 0x05, 0x80, 0x5d, 0xe6, 0x83,
+ 0x82, 0xac, 0x80, 0x42, 0x84, 0x81, 0xc9, 0x81,
+ 0x45, 0x2a, 0x84, 0x60, 0x45, 0xf8, 0x81, 0x40,
+ 0x84, 0x80, 0xc0, 0x82, 0x89, 0x80, 0x43, 0x51,
+ 0x81, 0x60, 0x4e, 0x05, 0x80, 0x5d, 0xe6, 0x83,
};
-static const uint8_t unicode_prop_Unified_Ideograph_table[42] = {
+static const uint8_t unicode_prop_Unified_Ideograph_table[45] = {
0x60, 0x33, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x51,
0xff, 0x60, 0x5a, 0x0d, 0x08, 0x00, 0x81, 0x89,
0x00, 0x00, 0x09, 0x82, 0x61, 0x05, 0xd5, 0x60,
- 0xa6, 0xdf, 0x9f, 0x50, 0x38, 0x86, 0x40, 0xdd,
+ 0xa6, 0xdf, 0x9f, 0x50, 0x39, 0x85, 0x40, 0xdd,
0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x54, 0x1e,
- 0x53, 0x4a,
+ 0x53, 0x4a, 0x84, 0x50, 0x5f,
};
static const uint8_t unicode_prop_Variation_Selector_table[13] = {
@@ -4125,11 +4232,11 @@ static const uint8_t unicode_prop_Emoji_table[239] = {
0xbe, 0x8a, 0x28, 0x97, 0x31, 0x0f, 0x8b, 0x01,
0x19, 0x03, 0x81, 0x8c, 0x09, 0x07, 0x81, 0x88,
0x04, 0x82, 0x8b, 0x17, 0x11, 0x00, 0x03, 0x05,
- 0x02, 0x05, 0xd5, 0xaf, 0xc5, 0x27, 0x0a, 0x84,
- 0x88, 0x10, 0x01, 0x10, 0x81, 0x89, 0x40, 0xe2,
+ 0x02, 0x05, 0xd5, 0xaf, 0xc5, 0x27, 0x0a, 0x83,
+ 0x89, 0x10, 0x01, 0x10, 0x81, 0x89, 0x40, 0xe2,
0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, 0x89, 0x80,
- 0x40, 0xb8, 0xef, 0x22, 0x22, 0x86, 0x88, 0x9c,
- 0x82, 0x8a, 0x25, 0x89, 0x89, 0x2f, 0x3e,
+ 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x88, 0x86, 0xad,
+ 0x06, 0x87, 0x8d, 0x83, 0x88, 0x86, 0x88,
};
static const uint8_t unicode_prop_Emoji_Component_table[28] = {
@@ -4152,7 +4259,7 @@ static const uint8_t unicode_prop_Emoji_Modifier_Base_table[71] = {
0xd2, 0x80, 0x8f, 0x82, 0x88, 0x80, 0x8a, 0x80,
0x42, 0x3e, 0x01, 0x07, 0x3d, 0x80, 0x88, 0x89,
0x0a, 0xb7, 0x80, 0xbc, 0x08, 0x08, 0x80, 0x90,
- 0x10, 0x8c, 0x40, 0xe4, 0x82, 0xa9, 0x86,
+ 0x10, 0x8c, 0x40, 0xe4, 0x82, 0xa9, 0x88,
};
static const uint8_t unicode_prop_Emoji_Presentation_table[145] = {
@@ -4170,11 +4277,11 @@ static const uint8_t unicode_prop_Emoji_Presentation_table[145] = {
0x1c, 0x8b, 0x90, 0x10, 0x82, 0xc6, 0x00, 0x80,
0x40, 0xba, 0x81, 0xbe, 0x8c, 0x18, 0x97, 0x91,
0x80, 0x99, 0x81, 0x8c, 0x80, 0xd5, 0xd4, 0xaf,
- 0xc5, 0x28, 0x12, 0x0a, 0x22, 0x8a, 0x0e, 0x88,
+ 0xc5, 0x28, 0x12, 0x0a, 0x1b, 0x8a, 0x0e, 0x88,
0x40, 0xe2, 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80,
- 0x89, 0x80, 0x40, 0xb8, 0xef, 0x22, 0x22, 0x86,
- 0x88, 0x9c, 0x82, 0x8a, 0x25, 0x89, 0x89, 0x2f,
- 0x3e,
+ 0x89, 0x80, 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x88,
+ 0x86, 0xad, 0x06, 0x87, 0x8d, 0x83, 0x88, 0x86,
+ 0x88,
};
static const uint8_t unicode_prop_Extended_Pictographic_table[156] = {
@@ -4447,3 +4554,4 @@ static const uint16_t unicode_prop_len_table[] = {
};
#endif /* CONFIG_ALL_UNICODE */
+/* 62 tables / 32261 bytes, 5 index / 345 bytes */
diff --git a/src/shared/quickjs/libunicode.c b/src/shared/quickjs/libunicode.c
index 112da72da..482c51944 100644
--- a/src/shared/quickjs/libunicode.c
+++ b/src/shared/quickjs/libunicode.c
@@ -43,11 +43,111 @@ enum {
RUN_TYPE_UF_D1_EXT,
RUN_TYPE_U_EXT,
RUN_TYPE_LF_EXT,
- RUN_TYPE_U_EXT2,
- RUN_TYPE_L_EXT2,
- RUN_TYPE_U_EXT3,
+ RUN_TYPE_UF_EXT2,
+ RUN_TYPE_LF_EXT2,
+ RUN_TYPE_UF_EXT3,
};
+static int lre_case_conv1(uint32_t c, int conv_type)
+{
+ uint32_t res[LRE_CC_RES_LEN_MAX];
+ lre_case_conv(res, c, conv_type);
+ return res[0];
+}
+
+/* case conversion using the table entry 'idx' with value 'v' */
+static int lre_case_conv_entry(uint32_t *res, uint32_t c, int conv_type, uint32_t idx, uint32_t v)
+{
+ uint32_t code, data, type, a, is_lower;
+ is_lower = (conv_type != 0);
+ type = (v >> (32 - 17 - 7 - 4)) & 0xf;
+ data = ((v & 0xf) << 8) | case_conv_table2[idx];
+ code = v >> (32 - 17);
+ switch(type) {
+ case RUN_TYPE_U:
+ case RUN_TYPE_L:
+ case RUN_TYPE_UF:
+ case RUN_TYPE_LF:
+ if (conv_type == (type & 1) ||
+ (type >= RUN_TYPE_UF && conv_type == 2)) {
+ c = c - code + (case_conv_table1[data] >> (32 - 17));
+ }
+ break;
+ case RUN_TYPE_UL:
+ a = c - code;
+ if ((a & 1) != (1 - is_lower))
+ break;
+ c = (a ^ 1) + code;
+ break;
+ case RUN_TYPE_LSU:
+ a = c - code;
+ if (a == 1) {
+ c += 2 * is_lower - 1;
+ } else if (a == (1 - is_lower) * 2) {
+ c += (2 * is_lower - 1) * 2;
+ }
+ break;
+ case RUN_TYPE_U2L_399_EXT2:
+ if (!is_lower) {
+ res[0] = c - code + case_conv_ext[data >> 6];
+ res[1] = 0x399;
+ return 2;
+ } else {
+ c = c - code + case_conv_ext[data & 0x3f];
+ }
+ break;
+ case RUN_TYPE_UF_D20:
+ if (conv_type == 1)
+ break;
+ c = data + (conv_type == 2) * 0x20;
+ break;
+ case RUN_TYPE_UF_D1_EXT:
+ if (conv_type == 1)
+ break;
+ c = case_conv_ext[data] + (conv_type == 2);
+ break;
+ case RUN_TYPE_U_EXT:
+ case RUN_TYPE_LF_EXT:
+ if (is_lower != (type - RUN_TYPE_U_EXT))
+ break;
+ c = case_conv_ext[data];
+ break;
+ case RUN_TYPE_LF_EXT2:
+ if (!is_lower)
+ break;
+ res[0] = c - code + case_conv_ext[data >> 6];
+ res[1] = case_conv_ext[data & 0x3f];
+ return 2;
+ case RUN_TYPE_UF_EXT2:
+ if (conv_type == 1)
+ break;
+ res[0] = c - code + case_conv_ext[data >> 6];
+ res[1] = case_conv_ext[data & 0x3f];
+ if (conv_type == 2) {
+ /* convert to lower */
+ res[0] = lre_case_conv1(res[0], 1);
+ res[1] = lre_case_conv1(res[1], 1);
+ }
+ return 2;
+ default:
+ case RUN_TYPE_UF_EXT3:
+ if (conv_type == 1)
+ break;
+ res[0] = case_conv_ext[data >> 8];
+ res[1] = case_conv_ext[(data >> 4) & 0xf];
+ res[2] = case_conv_ext[data & 0xf];
+ if (conv_type == 2) {
+ /* convert to lower */
+ res[0] = lre_case_conv1(res[0], 1);
+ res[1] = lre_case_conv1(res[1], 1);
+ res[2] = lre_case_conv1(res[2], 1);
+ }
+ return 3;
+ }
+ res[0] = c;
+ return 1;
+}
+
/* conv_type:
0 = to upper
1 = to lower
@@ -66,10 +166,9 @@ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type)
}
}
} else {
- uint32_t v, code, data, type, len, a, is_lower;
+ uint32_t v, code, len;
int idx, idx_min, idx_max;
- is_lower = (conv_type != 0);
idx_min = 0;
idx_max = countof(case_conv_table1) - 1;
while (idx_min <= idx_max) {
@@ -82,74 +181,7 @@ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type)
} else if (c >= code + len) {
idx_min = idx + 1;
} else {
- type = (v >> (32 - 17 - 7 - 4)) & 0xf;
- data = ((v & 0xf) << 8) | case_conv_table2[idx];
- switch(type) {
- case RUN_TYPE_U:
- case RUN_TYPE_L:
- case RUN_TYPE_UF:
- case RUN_TYPE_LF:
- if (conv_type == (type & 1) ||
- (type >= RUN_TYPE_UF && conv_type == 2)) {
- c = c - code + (case_conv_table1[data] >> (32 - 17));
- }
- break;
- case RUN_TYPE_UL:
- a = c - code;
- if ((a & 1) != (1 - is_lower))
- break;
- c = (a ^ 1) + code;
- break;
- case RUN_TYPE_LSU:
- a = c - code;
- if (a == 1) {
- c += 2 * is_lower - 1;
- } else if (a == (1 - is_lower) * 2) {
- c += (2 * is_lower - 1) * 2;
- }
- break;
- case RUN_TYPE_U2L_399_EXT2:
- if (!is_lower) {
- res[0] = c - code + case_conv_ext[data >> 6];
- res[1] = 0x399;
- return 2;
- } else {
- c = c - code + case_conv_ext[data & 0x3f];
- }
- break;
- case RUN_TYPE_UF_D20:
- if (conv_type == 1)
- break;
- c = data + (conv_type == 2) * 0x20;
- break;
- case RUN_TYPE_UF_D1_EXT:
- if (conv_type == 1)
- break;
- c = case_conv_ext[data] + (conv_type == 2);
- break;
- case RUN_TYPE_U_EXT:
- case RUN_TYPE_LF_EXT:
- if (is_lower != (type - RUN_TYPE_U_EXT))
- break;
- c = case_conv_ext[data];
- break;
- case RUN_TYPE_U_EXT2:
- case RUN_TYPE_L_EXT2:
- if (conv_type != (type - RUN_TYPE_U_EXT2))
- break;
- res[0] = c - code + case_conv_ext[data >> 6];
- res[1] = case_conv_ext[data & 0x3f];
- return 2;
- default:
- case RUN_TYPE_U_EXT3:
- if (conv_type != 0)
- break;
- res[0] = case_conv_ext[data >> 8];
- res[1] = case_conv_ext[(data >> 4) & 0xf];
- res[2] = case_conv_ext[data & 0xf];
- return 3;
- }
- break;
+ return lre_case_conv_entry(res, c, conv_type, idx, v);
}
}
}
@@ -157,13 +189,80 @@ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type)
return 1;
}
+static int lre_case_folding_entry(uint32_t c, uint32_t idx, uint32_t v, BOOL is_unicode)
+{
+ uint32_t res[LRE_CC_RES_LEN_MAX];
+ int len;
+
+ if (is_unicode) {
+ len = lre_case_conv_entry(res, c, 2, idx, v);
+ if (len == 1) {
+ c = res[0];
+ } else {
+ /* handle the few specific multi-character cases (see
+ unicode_gen.c:dump_case_folding_special_cases()) */
+ if (c == 0xfb06) {
+ c = 0xfb05;
+ } else if (c == 0x01fd3) {
+ c = 0x390;
+ } else if (c == 0x01fe3) {
+ c = 0x3b0;
+ }
+ }
+ } else {
+ if (likely(c < 128)) {
+ if (c >= 'a' && c <= 'z')
+ c = c - 'a' + 'A';
+ } else {
+ /* legacy regexp: to upper case if single char >= 128 */
+ len = lre_case_conv_entry(res, c, FALSE, idx, v);
+ if (len == 1 && res[0] >= 128)
+ c = res[0];
+ }
+ }
+ return c;
+}
+
+/* JS regexp specific rules for case folding */
+int lre_canonicalize(uint32_t c, BOOL is_unicode)
+{
+ if (c < 128) {
+ /* fast case */
+ if (is_unicode) {
+ if (c >= 'A' && c <= 'Z') {
+ c = c - 'A' + 'a';
+ }
+ } else {
+ if (c >= 'a' && c <= 'z') {
+ c = c - 'a' + 'A';
+ }
+ }
+ } else {
+ uint32_t v, code, len;
+ int idx, idx_min, idx_max;
+
+ idx_min = 0;
+ idx_max = countof(case_conv_table1) - 1;
+ while (idx_min <= idx_max) {
+ idx = (unsigned)(idx_max + idx_min) / 2;
+ v = case_conv_table1[idx];
+ code = v >> (32 - 17);
+ len = (v >> (32 - 17 - 7)) & 0x7f;
+ if (c < code) {
+ idx_max = idx - 1;
+ } else if (c >= code + len) {
+ idx_min = idx + 1;
+ } else {
+ return lre_case_folding_entry(c, idx, v, is_unicode);
+ }
+ }
+ }
+ return c;
+}
+
static uint32_t get_le24(const uint8_t *ptr)
{
-#if defined(__x86__) || defined(__x86_64__)
- return *(uint16_t *)ptr | (ptr[2] << 16);
-#else
return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16);
-#endif
}
#define UNICODE_INDEX_BLOCK_LEN 32
@@ -214,6 +313,14 @@ static BOOL lre_is_in_table(uint32_t c, const uint8_t *table,
return FALSE; /* outside the table */
p = table + pos;
bit = 0;
+ /* Compressed run length encoding:
+ 00..3F: 2 packed lengths: 3-bit + 3-bit
+ 40..5F: 5-bits plus extra byte for length
+ 60..7F: 5-bits plus 2 extra bytes for length
+ 80..FF: 7-bit length
+ lengths must be incremented to get character count
+ Ranges alternate between false and true return value.
+ */
for(;;) {
b = *p++;
if (b < 64) {
@@ -271,7 +378,7 @@ BOOL lre_is_case_ignorable(uint32_t c)
/* character range */
-static maybe_unused void cr_dump(CharRange *cr)
+static __maybe_unused void cr_dump(CharRange *cr)
{
int i;
for(i = 0; i < cr->len; i++)
@@ -327,7 +434,7 @@ static void cr_compress(CharRange *cr)
{
int i, j, k, len;
uint32_t *pt;
-
+
pt = cr->points;
len = cr->len;
i = 0;
@@ -730,6 +837,13 @@ static int unicode_get_cc(uint32_t c)
if (pos < 0)
return 0;
p = unicode_cc_table + pos;
+ /* Compressed run length encoding:
+ - 2 high order bits are combining class type
+ - 0:0, 1:230, 2:extra byte linear progression, 3:extra byte
+ - 00..2F: range length (add 1)
+ - 30..37: 3-bit range-length + 1 extra byte
+ - 38..3F: 3-bit range-length + 2 extra byte
+ */
for(;;) {
b = *p++;
type = b >> 6;
@@ -1082,6 +1196,15 @@ static int unicode_general_category1(CharRange *cr, uint32_t gc_mask)
p = unicode_gc_table;
p_end = unicode_gc_table + countof(unicode_gc_table);
c = 0;
+ /* Compressed range encoding:
+ initial byte:
+ bits 0..4: category number (special case 31)
+ bits 5..7: range length (add 1)
+ special case bits 5..7 == 7: read an extra byte
+ - 00..7F: range length (add 7 + 1)
+ - 80..BF: 6-bits plus extra byte for range length (add 7 + 128)
+ - C0..FF: 6-bits plus 2 extra bytes for range length (add 7 + 128 + 16384)
+ */
while (p < p_end) {
b = *p++;
n = b >> 5;
@@ -1135,6 +1258,14 @@ static int unicode_prop1(CharRange *cr, int prop_idx)
p_end = p + unicode_prop_len_table[prop_idx];
c = 0;
bit = 0;
+ /* Compressed range encoding:
+ 00..3F: 2 packed lengths: 3-bit + 3-bit
+ 40..5F: 5-bits plus extra byte for length
+ 60..7F: 5-bits plus 2 extra bytes for length
+ 80..FF: 7-bit length
+ lengths must be incremented to get character count
+ Ranges alternate between false and true return value.
+ */
while (p < p_end) {
c0 = c;
b = *p++;
@@ -1179,11 +1310,11 @@ static int unicode_case1(CharRange *cr, int case_mask)
#define MR(x) (1 << RUN_TYPE_ ## x)
const uint32_t tab_run_mask[3] = {
MR(U) | MR(UF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(UF_D20) |
- MR(UF_D1_EXT) | MR(U_EXT) | MR(U_EXT2) | MR(U_EXT3),
+ MR(UF_D1_EXT) | MR(U_EXT) | MR(UF_EXT2) | MR(UF_EXT3),
- MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(L_EXT2),
+ MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2),
- MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT),
+ MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT) | MR(UF_EXT2) | MR(UF_EXT3),
};
#undef MR
uint32_t mask, v, code, type, len, i, idx;
@@ -1237,6 +1368,135 @@ static int unicode_case1(CharRange *cr, int case_mask)
return 0;
}
+static int point_cmp(const void *p1, const void *p2, void *arg)
+{
+ uint32_t v1 = *(uint32_t *)p1;
+ uint32_t v2 = *(uint32_t *)p2;
+ return (v1 > v2) - (v1 < v2);
+}
+
+static void cr_sort_and_remove_overlap(CharRange *cr)
+{
+ uint32_t start, end, start1, end1, i, j;
+
+ /* the resulting ranges are not necessarily sorted and may overlap */
+ rqsort(cr->points, cr->len / 2, sizeof(cr->points[0]) * 2, point_cmp, NULL);
+ j = 0;
+ for(i = 0; i < cr->len; ) {
+ start = cr->points[i];
+ end = cr->points[i + 1];
+ i += 2;
+ while (i < cr->len) {
+ start1 = cr->points[i];
+ end1 = cr->points[i + 1];
+ if (start1 > end) {
+ /* |------|
+ * |-------| */
+ break;
+ } else if (end1 <= end) {
+ /* |------|
+ * |--| */
+ i += 2;
+ } else {
+ /* |------|
+ * |-------| */
+ end = end1;
+ i += 2;
+ }
+ }
+ cr->points[j] = start;
+ cr->points[j + 1] = end;
+ j += 2;
+ }
+ cr->len = j;
+}
+
+/* canonicalize a character set using the JS regex case folding rules
+ (see lre_canonicalize()) */
+int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode)
+{
+ CharRange cr_inter, cr_mask, cr_result, cr_sub;
+ uint32_t v, code, len, i, idx, start, end, c, d_start, d_end, d;
+
+ cr_init(&cr_mask, cr->mem_opaque, cr->realloc_func);
+ cr_init(&cr_inter, cr->mem_opaque, cr->realloc_func);
+ cr_init(&cr_result, cr->mem_opaque, cr->realloc_func);
+ cr_init(&cr_sub, cr->mem_opaque, cr->realloc_func);
+
+ if (unicode_case1(&cr_mask, is_unicode ? CASE_F : CASE_U))
+ goto fail;
+ if (cr_op(&cr_inter, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER))
+ goto fail;
+
+ if (cr_invert(&cr_mask))
+ goto fail;
+ if (cr_op(&cr_sub, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER))
+ goto fail;
+
+ /* cr_inter = cr & cr_mask */
+ /* cr_sub = cr & ~cr_mask */
+
+ /* use the case conversion table to compute the result */
+ d_start = -1;
+ d_end = -1;
+ idx = 0;
+ v = case_conv_table1[idx];
+ code = v >> (32 - 17);
+ len = (v >> (32 - 17 - 7)) & 0x7f;
+ for(i = 0; i < cr_inter.len; i += 2) {
+ start = cr_inter.points[i];
+ end = cr_inter.points[i + 1];
+
+ for(c = start; c < end; c++) {
+ for(;;) {
+ if (c >= code && c < code + len)
+ break;
+ idx++;
+ assert(idx < countof(case_conv_table1));
+ v = case_conv_table1[idx];
+ code = v >> (32 - 17);
+ len = (v >> (32 - 17 - 7)) & 0x7f;
+ }
+ d = lre_case_folding_entry(c, idx, v, is_unicode);
+ /* try to merge with the current interval */
+ if (d_start == -1) {
+ d_start = d;
+ d_end = d + 1;
+ } else if (d_end == d) {
+ d_end++;
+ } else {
+ cr_add_interval(&cr_result, d_start, d_end);
+ d_start = d;
+ d_end = d + 1;
+ }
+ }
+ }
+ if (d_start != -1) {
+ if (cr_add_interval(&cr_result, d_start, d_end))
+ goto fail;
+ }
+
+ /* the resulting ranges are not necessarily sorted and may overlap */
+ cr_sort_and_remove_overlap(&cr_result);
+
+ /* or with the character not affected by the case folding */
+ cr->len = 0;
+ if (cr_op(cr, cr_result.points, cr_result.len, cr_sub.points, cr_sub.len, CR_OP_UNION))
+ goto fail;
+
+ cr_free(&cr_inter);
+ cr_free(&cr_mask);
+ cr_free(&cr_result);
+ cr_free(&cr_sub);
+ return 0;
+ fail:
+ cr_free(&cr_inter);
+ cr_free(&cr_mask);
+ cr_free(&cr_result);
+ cr_free(&cr_sub);
+ return -1;
+}
+
typedef enum {
POP_GC,
POP_PROP,
@@ -1556,3 +1816,97 @@ int unicode_prop(CharRange *cr, const char *prop_name)
}
#endif /* CONFIG_ALL_UNICODE */
+
+/*---- lre codepoint categorizing functions ----*/
+
+#define S UNICODE_C_SPACE
+#define D UNICODE_C_DIGIT
+#define X UNICODE_C_XDIGIT
+#define U UNICODE_C_UPPER
+#define L UNICODE_C_LOWER
+#define _ UNICODE_C_UNDER
+#define d UNICODE_C_DOLLAR
+
+uint8_t const lre_ctype_bits[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, S, S, S, S, S, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ S, 0, 0, 0, d, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ X|D, X|D, X|D, X|D, X|D, X|D, X|D, X|D,
+ X|D, X|D, 0, 0, 0, 0, 0, 0,
+
+ 0, X|U, X|U, X|U, X|U, X|U, X|U, U,
+ U, U, U, U, U, U, U, U,
+ U, U, U, U, U, U, U, U,
+ U, U, U, 0, 0, 0, 0, _,
+
+ 0, X|L, X|L, X|L, X|L, X|L, X|L, L,
+ L, L, L, L, L, L, L, L,
+ L, L, L, L, L, L, L, L,
+ L, L, L, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ S, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+#undef S
+#undef D
+#undef X
+#undef U
+#undef L
+#undef _
+#undef d
+
+/* code point ranges for Zs,Zl or Zp property */
+static const uint16_t char_range_s[] = {
+ 10,
+ 0x0009, 0x000D + 1,
+ 0x0020, 0x0020 + 1,
+ 0x00A0, 0x00A0 + 1,
+ 0x1680, 0x1680 + 1,
+ 0x2000, 0x200A + 1,
+ /* 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; */
+ /* 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; */
+ 0x2028, 0x2029 + 1,
+ 0x202F, 0x202F + 1,
+ 0x205F, 0x205F + 1,
+ 0x3000, 0x3000 + 1,
+ /* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; */
+ 0xFEFF, 0xFEFF + 1,
+};
+
+BOOL lre_is_space_non_ascii(uint32_t c)
+{
+ size_t i, n;
+
+ n = countof(char_range_s);
+ for(i = 5; i < n; i += 2) {
+ uint32_t low = char_range_s[i];
+ uint32_t high = char_range_s[i + 1];
+ if (c < low)
+ return FALSE;
+ if (c < high)
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/src/shared/quickjs/libunicode.h b/src/shared/quickjs/libunicode.h
index cfa600a50..cc2f244c7 100644
--- a/src/shared/quickjs/libunicode.h
+++ b/src/shared/quickjs/libunicode.h
@@ -1,6 +1,6 @@
/*
* Unicode utilities
- *
+ *
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -24,26 +24,13 @@
#ifndef LIBUNICODE_H
#define LIBUNICODE_H
-#include <inttypes.h>
-
-#define LRE_BOOL int /* for documentation purposes */
+#include <stdint.h>
/* define it to include all the unicode tables (40KB larger) */
#define CONFIG_ALL_UNICODE
#define LRE_CC_RES_LEN_MAX 3
-typedef enum {
- UNICODE_NFC,
- UNICODE_NFD,
- UNICODE_NFKC,
- UNICODE_NFKD,
-} UnicodeNormalizationEnum;
-
-int lre_case_conv(uint32_t *res, uint32_t c, int conv_type);
-LRE_BOOL lre_is_cased(uint32_t c);
-LRE_BOOL lre_is_case_ignorable(uint32_t c);
-
/* char ranges */
typedef struct {
@@ -101,10 +88,14 @@ int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
int cr_invert(CharRange *cr);
-#ifdef CONFIG_ALL_UNICODE
+int cr_regexp_canonicalize(CharRange *cr, int is_unicode);
-LRE_BOOL lre_is_id_start(uint32_t c);
-LRE_BOOL lre_is_id_continue(uint32_t c);
+typedef enum {
+ UNICODE_NFC,
+ UNICODE_NFD,
+ UNICODE_NFKC,
+ UNICODE_NFKD,
+} UnicodeNormalizationEnum;
int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
UnicodeNormalizationEnum n_type,
@@ -112,13 +103,80 @@ int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
/* Unicode character range functions */
-int unicode_script(CharRange *cr,
- const char *script_name, LRE_BOOL is_ext);
+int unicode_script(CharRange *cr, const char *script_name, int is_ext);
int unicode_general_category(CharRange *cr, const char *gc_name);
int unicode_prop(CharRange *cr, const char *prop_name);
-#endif /* CONFIG_ALL_UNICODE */
+int lre_case_conv(uint32_t *res, uint32_t c, int conv_type);
+int lre_canonicalize(uint32_t c, int is_unicode);
+
+/* Code point type categories */
+enum {
+ UNICODE_C_SPACE = (1 << 0),
+ UNICODE_C_DIGIT = (1 << 1),
+ UNICODE_C_UPPER = (1 << 2),
+ UNICODE_C_LOWER = (1 << 3),
+ UNICODE_C_UNDER = (1 << 4),
+ UNICODE_C_DOLLAR = (1 << 5),
+ UNICODE_C_XDIGIT = (1 << 6),
+};
+extern uint8_t const lre_ctype_bits[256];
+
+/* zero or non-zero return value */
+int lre_is_cased(uint32_t c);
+int lre_is_case_ignorable(uint32_t c);
+int lre_is_id_start(uint32_t c);
+int lre_is_id_continue(uint32_t c);
+
+static inline int lre_is_space_byte(uint8_t c) {
+ return lre_ctype_bits[c] & UNICODE_C_SPACE;
+}
+
+static inline int lre_is_id_start_byte(uint8_t c) {
+ return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER |
+ UNICODE_C_UNDER | UNICODE_C_DOLLAR);
+}
-#undef LRE_BOOL
+static inline int lre_is_id_continue_byte(uint8_t c) {
+ return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER |
+ UNICODE_C_UNDER | UNICODE_C_DOLLAR |
+ UNICODE_C_DIGIT);
+}
+
+int lre_is_space_non_ascii(uint32_t c);
+
+static inline int lre_is_space(uint32_t c) {
+ if (c < 256)
+ return lre_is_space_byte(c);
+ else
+ return lre_is_space_non_ascii(c);
+}
+
+static inline int lre_js_is_ident_first(uint32_t c) {
+ if (c < 128) {
+ return lre_is_id_start_byte(c);
+ } else {
+#ifdef CONFIG_ALL_UNICODE
+ return lre_is_id_start(c);
+#else
+ return !lre_is_space_non_ascii(c);
+#endif
+ }
+}
+
+static inline int lre_js_is_ident_next(uint32_t c) {
+ if (c < 128) {
+ return lre_is_id_continue_byte(c);
+ } else {
+ /* ZWNJ and ZWJ are accepted in identifiers */
+ if (c >= 0x200C && c <= 0x200D)
+ return TRUE;
+#ifdef CONFIG_ALL_UNICODE
+ return lre_is_id_continue(c);
+#else
+ return !lre_is_space_non_ascii(c);
+#endif
+ }
+}
#endif /* LIBUNICODE_H */
diff --git a/src/shared/quickjs/list.h b/src/shared/quickjs/list.h
index e7f51a9d9..809831115 100644
--- a/src/shared/quickjs/list.h
+++ b/src/shared/quickjs/list.h
@@ -36,8 +36,7 @@ struct list_head {
#define LIST_HEAD_INIT(el) { &(el), &(el) }
/* return the pointer of type 'type *' containing 'el' as field 'member' */
-#define list_entry(el, type, member) \
- ((type *)((uint8_t *)(el) - offsetof(type, member)))
+#define list_entry(el, type, member) container_of(el, type, member)
static inline void init_list_head(struct list_head *head)
{
@@ -46,8 +45,8 @@ static inline void init_list_head(struct list_head *head)
}
/* insert 'el' between 'prev' and 'next' */
-static inline void list_add_impl(struct list_head *el,
- struct list_head *prev, struct list_head *next)
+static inline void __list_add(struct list_head *el,
+ struct list_head *prev, struct list_head *next)
{
prev->next = el;
el->prev = prev;
@@ -58,13 +57,13 @@ static inline void list_add_impl(struct list_head *el,
/* add 'el' at the head of the list 'head' (= after element head) */
static inline void list_add(struct list_head *el, struct list_head *head)
{
- list_add_impl(el, head, head->next);
+ __list_add(el, head, head->next);
}
/* add 'el' at the end of the list 'head' (= before element head) */
static inline void list_add_tail(struct list_head *el, struct list_head *head)
{
- list_add_impl(el, head->prev, head);
+ __list_add(el, head->prev, head);
}
static inline void list_del(struct list_head *el)
diff --git a/src/shared/quickjs/quickjs-atom.h b/src/shared/quickjs/quickjs-atom.h
index 4c2279452..f4d5838d4 100644
--- a/src/shared/quickjs/quickjs-atom.h
+++ b/src/shared/quickjs/quickjs-atom.h
@@ -1,6 +1,6 @@
/*
* QuickJS atom definitions
- *
+ *
* Copyright (c) 2017-2018 Fabrice Bellard
* Copyright (c) 2017-2018 Charlie Gordon
*
@@ -82,6 +82,7 @@ DEF(length, "length")
DEF(fileName, "fileName")
DEF(lineNumber, "lineNumber")
DEF(message, "message")
+DEF(cause, "cause")
DEF(errors, "errors")
DEF(stack, "stack")
DEF(name, "name")
@@ -166,22 +167,23 @@ DEF(revoke, "revoke")
DEF(async, "async")
DEF(exec, "exec")
DEF(groups, "groups")
+DEF(indices, "indices")
DEF(status, "status")
DEF(reason, "reason")
DEF(globalThis, "globalThis")
-#ifdef CONFIG_BIGNUM
DEF(bigint, "bigint")
+#ifdef CONFIG_BIGNUM
DEF(bigfloat, "bigfloat")
DEF(bigdecimal, "bigdecimal")
DEF(roundingMode, "roundingMode")
DEF(maximumSignificantDigits, "maximumSignificantDigits")
DEF(maximumFractionDigits, "maximumFractionDigits")
#endif
-#ifdef CONFIG_ATOMICS
+/* the following 3 atoms are only used with CONFIG_ATOMICS */
DEF(not_equal, "not-equal")
DEF(timed_out, "timed-out")
DEF(ok, "ok")
-#endif
+/* */
DEF(toJSON, "toJSON")
/* class names */
DEF(Object, "Object")
@@ -202,22 +204,20 @@ DEF(RegExp, "RegExp")
DEF(ArrayBuffer, "ArrayBuffer")
DEF(SharedArrayBuffer, "SharedArrayBuffer")
/* must keep same order as class IDs for typed arrays */
-DEF(Uint8ClampedArray, "Uint8ClampedArray")
+DEF(Uint8ClampedArray, "Uint8ClampedArray")
DEF(Int8Array, "Int8Array")
DEF(Uint8Array, "Uint8Array")
DEF(Int16Array, "Int16Array")
DEF(Uint16Array, "Uint16Array")
DEF(Int32Array, "Int32Array")
DEF(Uint32Array, "Uint32Array")
-#ifdef CONFIG_BIGNUM
DEF(BigInt64Array, "BigInt64Array")
DEF(BigUint64Array, "BigUint64Array")
-#endif
DEF(Float32Array, "Float32Array")
DEF(Float64Array, "Float64Array")
DEF(DataView, "DataView")
-#ifdef CONFIG_BIGNUM
DEF(BigInt, "BigInt")
+#ifdef CONFIG_BIGNUM
DEF(BigFloat, "BigFloat")
DEF(BigFloatEnv, "BigFloatEnv")
DEF(BigDecimal, "BigDecimal")
@@ -269,5 +269,5 @@ DEF(Symbol_asyncIterator, "Symbol.asyncIterator")
#ifdef CONFIG_BIGNUM
DEF(Symbol_operatorSet, "Symbol.operatorSet")
#endif
-
+
#endif /* DEF */
diff --git a/src/shared/quickjs/quickjs-opcode.h b/src/shared/quickjs/quickjs-opcode.h
index c731a14a9..1e1821259 100644
--- a/src/shared/quickjs/quickjs-opcode.h
+++ b/src/shared/quickjs/quickjs-opcode.h
@@ -1,6 +1,6 @@
/*
* QuickJS opcode definitions
- *
+ *
* Copyright (c) 2017-2018 Fabrice Bellard
* Copyright (c) 2017-2018 Charlie Gordon
*
@@ -165,14 +165,15 @@ DEF( set_loc, 3, 1, 1, loc) /* must come after put_loc */
DEF( get_arg, 3, 0, 1, arg)
DEF( put_arg, 3, 1, 0, arg) /* must come after get_arg */
DEF( set_arg, 3, 1, 1, arg) /* must come after put_arg */
-DEF( get_var_ref, 3, 0, 1, var_ref)
+DEF( get_var_ref, 3, 0, 1, var_ref)
DEF( put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */
DEF( set_var_ref, 3, 1, 1, var_ref) /* must come after put_var_ref */
DEF(set_loc_uninitialized, 3, 0, 0, loc)
DEF( get_loc_check, 3, 0, 1, loc)
DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */
DEF( put_loc_check_init, 3, 1, 0, loc)
-DEF(get_var_ref_check, 3, 0, 1, var_ref)
+DEF(get_loc_checkthis, 3, 0, 1, loc)
+DEF(get_var_ref_check, 3, 0, 1, var_ref)
DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */
DEF(put_var_ref_check_init, 3, 1, 0, var_ref)
DEF( close_loc, 3, 0, 0, loc)
@@ -182,6 +183,7 @@ DEF( goto, 5, 0, 0, label) /* must come after if_true */
DEF( catch, 5, 0, 1, label)
DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */
DEF( ret, 1, 1, 0, none) /* used to return from the finally block */
+DEF( nip_catch, 1, 2, 1, none) /* catch ... a -> a */
DEF( to_object, 1, 1, 1, none)
//DEF( to_string, 1, 1, 1, none)
@@ -208,7 +210,6 @@ DEF( for_of_next, 2, 3, 5, u8)
DEF(iterator_check_object, 1, 1, 1, none)
DEF(iterator_get_value_done, 1, 1, 2, none)
DEF( iterator_close, 1, 3, 0, none)
-DEF(iterator_close_return, 1, 4, 4, none)
DEF( iterator_next, 1, 4, 4, none)
DEF( iterator_call, 2, 4, 5, u8)
DEF( initial_yield, 1, 0, 0, none)
@@ -256,12 +257,13 @@ DEF( and, 1, 2, 1, none)
DEF( xor, 1, 2, 1, none)
DEF( or, 1, 2, 1, none)
DEF(is_undefined_or_null, 1, 1, 1, none)
+DEF( private_in, 1, 2, 1, none)
#ifdef CONFIG_BIGNUM
DEF( mul_pow10, 1, 2, 1, none)
DEF( math_mod, 1, 2, 1, none)
#endif
/* must be the last non short and non temporary opcode */
-DEF( nop, 1, 0, 0, none)
+DEF( nop, 1, 0, 0, none)
/* temporary opcodes: never emitted in the final bytecode */
@@ -270,6 +272,8 @@ def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */
+/* the following opcodes must be in the same order as the 'with_x' and
+ get_var_undef, get_var and put_var opcodes */
def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */
@@ -277,12 +281,15 @@ def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase
def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */
def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
+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 */
def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */
def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */
-def(scope_put_private_field, 7, 1, 1, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */
-
+def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */
+def(scope_in_private_field, 7, 1, 1, atom_u16) /* obj -> res emitted in phase 1, removed in phase 2 */
+def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */
+def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */
def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */
-
+
def( line_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */
#if SHORT_OPCODES
diff --git a/src/shared/quickjs/quickjs.c b/src/shared/quickjs/quickjs.c
index f90fb9e4f..3bafe6948 100644
--- a/src/shared/quickjs/quickjs.c
+++ b/src/shared/quickjs/quickjs.c
@@ -58,9 +58,8 @@
#include "list.h"
#include "quickjs.h"
#include "libregexp.h"
-#ifdef CONFIG_BIGNUM
+#include "libunicode.h"
#include "libbf.h"
-#endif
#define OPTIMIZE 0
#define SHORT_OPCODES 1
@@ -102,6 +101,7 @@
8: dump stdlib functions
16: dump bytecode in hex
32: dump line number table
+ 64: dump compute_stack_size
*/
//#define DUMP_BYTECODE (1)
/* dump the occurence of the automatic GC */
@@ -176,15 +176,13 @@ enum {
JS_CLASS_UINT16_ARRAY, /* u.array (typed_array) */
JS_CLASS_INT32_ARRAY, /* u.array (typed_array) */
JS_CLASS_UINT32_ARRAY, /* u.array (typed_array) */
-#ifdef CONFIG_BIGNUM
JS_CLASS_BIG_INT64_ARRAY, /* u.array (typed_array) */
JS_CLASS_BIG_UINT64_ARRAY, /* u.array (typed_array) */
-#endif
JS_CLASS_FLOAT32_ARRAY, /* u.array (typed_array) */
JS_CLASS_FLOAT64_ARRAY, /* u.array (typed_array) */
JS_CLASS_DATAVIEW, /* u.typed_array */
-#ifdef CONFIG_BIGNUM
JS_CLASS_BIG_INT, /* u.object_data */
+#ifdef CONFIG_BIGNUM
JS_CLASS_BIG_FLOAT, /* u.object_data */
JS_CLASS_FLOAT_ENV, /* u.float_env */
JS_CLASS_BIG_DECIMAL, /* u.object_data */
@@ -232,14 +230,14 @@ typedef enum JSErrorEnum {
JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */
} JSErrorEnum;
-#define JS_MAX_LOCAL_VARS 65536
+#define JS_MAX_LOCAL_VARS 65535
#define JS_STACK_SIZE_MAX 65534
#define JS_STRING_LEN_MAX ((1 << 30) - 1)
#ifdef __GNUC__
-#define warn_unused __attribute__((warn_unused_result))
+#define __exception __attribute__((warn_unused_result))
#else
-#define warn_unused
+#define __exception
#endif
typedef struct JSShape JSShape;
@@ -254,7 +252,6 @@ typedef enum {
typedef enum OPCodeEnum OPCodeEnum;
-#ifdef CONFIG_BIGNUM
/* function pointers are used for numeric operations so that it is
possible to remove some numeric types */
typedef struct {
@@ -272,7 +269,6 @@ typedef struct {
int64_t exponent);
int (*mul_pow10)(JSContext *ctx, JSValue *sp);
} JSNumericOperations;
-#endif
struct JSRuntime {
JSMallocFunctions mf;
@@ -324,6 +320,8 @@ struct JSRuntime {
JSModuleNormalizeFunc *module_normalize_func;
JSModuleLoaderFunc *module_loader_func;
void *module_loader_opaque;
+ /* timestamp for internal use in module evaluation */
+ int64_t module_async_evaluation_next_timestamp;
BOOL can_block : 8; /* TRUE if Atomics.wait can block */
/* used to allocate, free and clone SharedArrayBuffers */
@@ -334,9 +332,9 @@ struct JSRuntime {
int shape_hash_size;
int shape_hash_count; /* number of hashed shapes */
JSShape **shape_hash;
-#ifdef CONFIG_BIGNUM
bf_context_t bf_ctx;
JSNumericOperations bigint_ops;
+#ifdef CONFIG_BIGNUM
JSNumericOperations bigfloat_ops;
JSNumericOperations bigdecimal_ops;
uint32_t operator_count;
@@ -357,17 +355,18 @@ struct JSClass {
#define JS_MODE_STRICT (1 << 0)
#define JS_MODE_STRIP (1 << 1)
#define JS_MODE_MATH (1 << 2)
+#define JS_MODE_ASYNC (1 << 3) /* async function */
typedef struct JSStackFrame {
struct JSStackFrame *prev_frame; /* NULL if first stack frame */
JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */
JSValue *arg_buf; /* arguments */
JSValue *var_buf; /* variables */
- struct list_head var_ref_list; /* list of JSVarRef.link */
+ struct list_head var_ref_list; /* list of JSVarRef.var_ref_link */
const uint8_t *cur_pc; /* only used in bytecode functions : PC of the
instruction after the call */
int arg_count;
- int js_mode; /* 0 or JS_MODE_MATH for C functions */
+ int js_mode; /* for C functions, only JS_MODE_MATH may be set */
/* only used in generators. Current stack pointer value. NULL if
the function is running. */
JSValue *cur_sp;
@@ -398,13 +397,8 @@ typedef struct JSVarRef {
union {
JSGCObjectHeader header; /* must come first */
struct {
- int _gc_ref_count; /* corresponds to header.ref_count */
- uint8_t _gc_mark; /* corresponds to header.mark/gc_obj_type */
-
- /* 0 : the JSVarRef is on the stack. header.link is an element
- of JSStackFrame.var_ref_list.
- 1 : the JSVarRef is detached. header.link has the normal meanning
- */
+ int __gc_ref_count; /* corresponds to header.ref_count */
+ uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
uint8_t is_detached : 1;
uint8_t is_arg : 1;
uint16_t var_idx; /* index of the corresponding function variable on
@@ -413,16 +407,15 @@ typedef struct JSVarRef {
};
JSValue *pvalue; /* pointer to the value, either on the stack or
to 'value' */
- JSValue value; /* used when the variable is no longer on the stack */
+ union {
+ JSValue value; /* used when is_detached = TRUE */
+ struct {
+ struct list_head var_ref_link; /* JSStackFrame.var_ref_list list */
+ struct JSAsyncFunctionState *async_func; /* != NULL if async stack frame */
+ }; /* used when is_detached = FALSE */
+ };
} JSVarRef;
-#ifdef CONFIG_BIGNUM
-typedef struct JSFloatEnv {
- limb_t prec;
- bf_flags_t flags;
- unsigned int status;
-} JSFloatEnv;
-
/* the same structure is used for big integers and big floats. Big
integers are never infinite or NaNs */
typedef struct JSBigFloat {
@@ -430,6 +423,13 @@ typedef struct JSBigFloat {
bf_t num;
} JSBigFloat;
+#ifdef CONFIG_BIGNUM
+typedef struct JSFloatEnv {
+ limb_t prec;
+ bf_flags_t flags;
+ unsigned int status;
+} JSFloatEnv;
+
typedef struct JSBigDecimal {
JSRefCountHeader header; /* must come first, 32-bit */
bfdec_t num;
@@ -473,15 +473,14 @@ struct JSContext {
JSValue global_var_obj; /* contains the global let/const definitions */
uint64_t random_state;
-#ifdef CONFIG_BIGNUM
bf_context_t *bf_ctx; /* points to rt->bf_ctx, shared by all contexts */
+#ifdef CONFIG_BIGNUM
JSFloatEnv fp_env; /* global FP environment */
BOOL bignum_ext : 8; /* enable math mode */
BOOL allow_operator_overloading : 8;
#endif
/* when the counter reaches zero, JSRutime.interrupt_handler is called */
int interrupt_counter;
- BOOL is_error_property_enabled;
struct list_head loaded_modules; /* list of JSModuleDef.link */
@@ -598,6 +597,7 @@ typedef struct JSVarDef {
uint8_t is_const : 1;
uint8_t is_lexical : 1;
uint8_t is_captured : 1;
+ uint8_t is_static_private : 1; /* only used during private class field parsing */
uint8_t var_kind : 4; /* see JSVarKindEnum */
/* only used during compilation: function pool index for lexical
variables with var_kind =
@@ -638,7 +638,8 @@ typedef struct JSFunctionBytecode {
uint8_t has_debug : 1;
uint8_t backtrace_barrier : 1; /* stop backtrace on this function */
uint8_t read_only_bytecode : 1;
- /* XXX: 4 bits available */
+ uint8_t is_direct_or_indirect_eval : 1; /* used by JS_GetScriptOrModuleName() */
+ /* XXX: 10 bits available */
uint8_t *byte_code_buf; /* (self pointer) */
int byte_code_len;
JSAtom func_name;
@@ -678,9 +679,11 @@ typedef enum JSIteratorKindEnum {
typedef struct JSForInIterator {
JSValue obj;
- BOOL is_array;
- uint32_t array_length;
uint32_t idx;
+ uint32_t atom_count;
+ uint8_t in_prototype_chain;
+ uint8_t is_array;
+ JSPropertyEnum *tab_atom; /* is_array = FALSE */
} JSForInIterator;
typedef struct JSRegExp {
@@ -714,21 +717,16 @@ typedef struct JSTypedArray {
} JSTypedArray;
typedef struct JSAsyncFunctionState {
- JSValue this_val; /* 'this' generator argument */
+ JSGCObjectHeader header;
+ JSValue this_val; /* 'this' argument */
int argc; /* number of function arguments */
BOOL throw_flag; /* used to throw an exception in JS_CallInternal() */
+ BOOL is_completed; /* TRUE if the function has returned. The stack
+ frame is no longer valid */
+ JSValue resolving_funcs[2]; /* only used in JS async functions */
JSStackFrame frame;
} JSAsyncFunctionState;
-/* XXX: could use an object instead to avoid the
- JS_TAG_ASYNC_FUNCTION tag for the GC */
-typedef struct JSAsyncFunctionData {
- JSGCObjectHeader header; /* must come first */
- JSValue resolving_funcs[2];
- BOOL is_active; /* true if the async function state is valid */
- JSAsyncFunctionState func_state;
-} JSAsyncFunctionData;
-
typedef enum {
/* binary operators */
JS_OVOP_ADD,
@@ -810,6 +808,15 @@ typedef struct JSImportEntry {
int req_module_idx; /* in req_module_entries */
} JSImportEntry;
+typedef enum {
+ JS_MODULE_STATUS_UNLINKED,
+ JS_MODULE_STATUS_LINKING,
+ JS_MODULE_STATUS_LINKED,
+ JS_MODULE_STATUS_EVALUATING,
+ JS_MODULE_STATUS_EVALUATING_ASYNC,
+ JS_MODULE_STATUS_EVALUATED,
+} JSModuleStatus;
+
struct JSModuleDef {
JSRefCountHeader header; /* must come first, 32-bit */
JSAtom module_name;
@@ -834,11 +841,24 @@ struct JSModuleDef {
JSValue module_ns;
JSValue func_obj; /* only used for JS modules */
JSModuleInitFunc *init_func; /* only used for C modules */
+ BOOL has_tla : 8; /* true if func_obj contains await */
BOOL resolved : 8;
BOOL func_created : 8;
- BOOL instantiated : 8;
- BOOL evaluated : 8;
- BOOL eval_mark : 8; /* temporary use during js_evaluate_module() */
+ JSModuleStatus status : 8;
+ /* temp use during js_module_link() & js_module_evaluate() */
+ int dfs_index, dfs_ancestor_index;
+ JSModuleDef *stack_prev;
+ /* temp use during js_module_evaluate() */
+ JSModuleDef **async_parent_modules;
+ int async_parent_modules_count;
+ int async_parent_modules_size;
+ int pending_async_dependencies;
+ BOOL async_evaluation;
+ int64_t async_evaluation_timestamp;
+ JSModuleDef *cycle_root;
+ JSValue promise; /* corresponds to spec field: capability */
+ JSValue resolving_funcs[2]; /* corresponds to spec field: capability */
+
/* true if evaluation yielded an exception. It is saved in
eval_exception */
BOOL eval_has_exception : 8;
@@ -907,8 +927,8 @@ struct JSObject {
union {
JSGCObjectHeader header;
struct {
- int _gc_ref_count; /* corresponds to header.ref_count */
- uint8_t _gc_mark; /* corresponds to header.mark/gc_obj_type */
+ int __gc_ref_count; /* corresponds to header.ref_count */
+ uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
uint8_t extensible : 1;
uint8_t free_mark : 1; /* only used when freeing objects with cycles */
@@ -946,7 +966,7 @@ struct JSObject {
struct JSProxyData *proxy_data; /* JS_CLASS_PROXY */
struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */
struct JSPromiseFunctionData *promise_function_data; /* JS_CLASS_PROMISE_RESOLVE_FUNCTION, JS_CLASS_PROMISE_REJECT_FUNCTION */
- struct JSAsyncFunctionData *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */
+ struct JSAsyncFunctionState *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */
struct JSAsyncFromSyncIteratorData *async_from_sync_iterator_data; /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
struct JSAsyncGeneratorData *async_generator_data; /* JS_CLASS_ASYNC_GENERATOR */
struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */
@@ -989,8 +1009,9 @@ struct JSObject {
} u;
/* byte sizes: 40/48/72 */
};
+
enum {
- JS_ATOM_NULL_ = JS_ATOM_NULL,
+ __JS_ATOM_NULL = JS_ATOM_NULL,
#define DEF(name, str) JS_ATOM_ ## name,
#include "quickjs-atom.h"
#undef DEF
@@ -1036,8 +1057,8 @@ enum OPCodeEnum {
};
static int JS_InitAtoms(JSRuntime *rt);
-static JSAtom JS_NewAtomInitImpl(JSRuntime *rt, const char *str, int len,
- int atom_type);
+static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
+ int atom_type);
static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p);
static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b);
static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
@@ -1057,34 +1078,29 @@ static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_o
int argc, JSValueConst *argv);
static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
int argc, JSValueConst *argv);
-static warn_unused int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
+static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
JSValue val, BOOL is_array_ctor);
static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
JSValueConst val, int flags, int scope_idx);
-static maybe_unused void JS_DumpAtoms(JSRuntime *rt);
-static maybe_unused void JS_DumpString(JSRuntime *rt,
- const JSString *p);
-static maybe_unused void JS_DumpObjectHeader(JSRuntime *rt);
-static maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p);
-static maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p);
-static maybe_unused void JS_DumpValueShort(JSRuntime *rt,
- JSValueConst val);
-static maybe_unused void JS_DumpValue(JSContext *ctx, JSValueConst val);
-static maybe_unused void JS_PrintValue(JSContext *ctx,
+static __maybe_unused void JS_DumpAtoms(JSRuntime *rt);
+static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p);
+static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt);
+static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p);
+static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p);
+static __maybe_unused void JS_DumpValueShort(JSRuntime *rt, JSValueConst val);
+static __maybe_unused void JS_DumpValue(JSContext *ctx, JSValueConst val);
+static __maybe_unused void JS_PrintValue(JSContext *ctx,
const char *str,
JSValueConst val);
-static maybe_unused void JS_DumpShapes(JSRuntime *rt);
+static __maybe_unused void JS_DumpShapes(JSRuntime *rt);
static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic);
static void js_array_finalizer(JSRuntime *rt, JSValue val);
-static void js_array_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
+static void js_array_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
static void js_object_data_finalizer(JSRuntime *rt, JSValue val);
-static void js_object_data_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
+static void js_object_data_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
static void js_c_function_finalizer(JSRuntime *rt, JSValue val);
-static void js_c_function_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
+static void js_c_function_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val);
static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
JS_MarkFunc *mark_func);
@@ -1128,6 +1144,12 @@ static void js_operator_set_finalizer(JSRuntime *rt, JSValue val);
static void js_operator_set_mark(JSRuntime *rt, JSValueConst val,
JS_MarkFunc *mark_func);
#endif
+
+#define HINT_STRING 0
+#define HINT_NUMBER 1
+#define HINT_NONE 2
+#define HINT_FORCE_ORDINARY (1 << 4) // don't try Symbol.toPrimitive
+static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint);
static JSValue JS_ToStringFree(JSContext *ctx, JSValue val);
static int JS_ToBoolFree(JSContext *ctx, JSValue val);
static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val);
@@ -1149,13 +1171,25 @@ typedef enum JSStrictEqModeEnum {
static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
JSStrictEqModeEnum eq_mode);
-static BOOL js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2);
+static BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2);
static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2);
static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2);
static JSValue JS_ToObject(JSContext *ctx, JSValueConst val);
static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val);
static JSProperty *add_property(JSContext *ctx,
JSObject *p, JSAtom prop, int prop_flags);
+static JSValue JS_NewBigInt(JSContext *ctx);
+static inline bf_t *JS_GetBigInt(JSValueConst val)
+{
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ return &p->num;
+}
+static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
+ BOOL convert_to_safe_integer);
+static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val);
+static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val);
+static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val);
+static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf);
#ifdef CONFIG_BIGNUM
static void js_float_env_finalizer(JSRuntime *rt, JSValue val);
static JSValue JS_NewBigFloat(JSContext *ctx);
@@ -1170,18 +1204,6 @@ static inline bfdec_t *JS_GetBigDecimal(JSValueConst val)
JSBigDecimal *p = JS_VALUE_GET_PTR(val);
return &p->num;
}
-static JSValue JS_NewBigInt(JSContext *ctx);
-static inline bf_t *JS_GetBigInt(JSValueConst val)
-{
- JSBigFloat *p = JS_VALUE_GET_PTR(val);
- return &p->num;
-}
-static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
- BOOL convert_to_safe_integer);
-static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val);
-static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val);
-static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val);
-static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf);
static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val);
static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
BOOL allow_null_or_undefined);
@@ -1191,9 +1213,10 @@ static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx);
static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj);
static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
JSValueConst proto_val, BOOL throw_flag);
+
+static int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, int throw_exception);
static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj);
static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj);
-static int js_proxy_isArray(JSContext *ctx, JSValueConst obj);
static int JS_CreateProperty(JSContext *ctx, JSObject *p,
JSAtom prop, JSValueConst val,
JSValueConst getter, JSValueConst setter,
@@ -1211,11 +1234,17 @@ static JSValue js_typed_array_constructor(JSContext *ctx,
JSValueConst this_val,
int argc, JSValueConst *argv,
int classid);
+static JSValue js_typed_array_constructor_ta(JSContext *ctx,
+ JSValueConst new_target,
+ JSValueConst src_obj,
+ int classid);
static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p);
static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p);
static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx);
static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx,
BOOL is_arg);
+static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s);
+static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s);
static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
JSValueConst this_obj,
int argc, JSValueConst *argv,
@@ -1235,12 +1264,14 @@ static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref);
static JSValue js_new_promise_capability(JSContext *ctx,
JSValue *resolving_funcs,
JSValueConst ctor);
-static warn_unused int perform_promise_then(JSContext *ctx,
+static __exception int perform_promise_then(JSContext *ctx,
JSValueConst promise,
JSValueConst *resolve_reject,
JSValueConst *cap_resolving_funcs);
static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic);
+static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv);
static int js_string_compare(JSContext *ctx,
const JSString *p1, const JSString *p2);
static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val);
@@ -1252,17 +1283,15 @@ static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val);
static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,
JSObject *p, JSAtom prop);
static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc);
-static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s,
- JS_MarkFunc *mark_func);
static void JS_AddIntrinsicBasicObjects(JSContext *ctx);
static void js_free_shape(JSRuntime *rt, JSShape *sh);
static void js_free_shape_null(JSRuntime *rt, JSShape *sh);
static int js_shape_prepare_update(JSContext *ctx, JSObject *p,
JSShapeProperty **pprs);
static int init_shape_hash(JSRuntime *rt);
-static warn_unused int js_get_length32(JSContext *ctx, uint32_t *pres,
+static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
JSValueConst obj);
-static warn_unused int js_get_length64(JSContext *ctx, int64_t *pres,
+static __exception int js_get_length64(JSContext *ctx, int64_t *pres,
JSValueConst obj);
static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len);
static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
@@ -1281,13 +1310,13 @@ static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val);
static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
JSGCObjectTypeEnum type);
static void remove_gc_object(JSGCObjectHeader *h);
-static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s);
static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
void *opaque);
static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
JSAtom atom, void *opaque);
-void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag);
+static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int is_map);
static const JSClassExoticMethods js_arguments_exotic_methods;
static const JSClassExoticMethods js_string_exotic_methods;
@@ -1349,14 +1378,12 @@ void *js_mallocz_rt(JSRuntime *rt, size_t size)
return memset(ptr, 0, size);
}
-#ifdef CONFIG_BIGNUM
/* called by libbf */
static void *js_bf_realloc(void *opaque, void *ptr, size_t size)
{
JSRuntime *rt = opaque;
return js_realloc_rt(rt, ptr, size);
}
-#endif /* CONFIG_BIGNUM */
/* Throw out of memory in case of error */
void *js_malloc(JSContext *ctx, size_t size)
@@ -1473,6 +1500,10 @@ static inline int is_digit(int c) {
return c >= '0' && c <= '9';
}
+static inline int string_get(const JSString *p, int idx) {
+ return p->is_wide_char ? p->u.str16[idx] : p->u.str8[idx];
+}
+
typedef struct JSClassShortDef {
JSAtom class_name;
JSClassFinalizer *finalizer;
@@ -1507,15 +1538,13 @@ static JSClassShortDef const js_std_class_def[] = {
{ JS_ATOM_Uint16Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT16_ARRAY */
{ JS_ATOM_Int32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_INT32_ARRAY */
{ JS_ATOM_Uint32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT32_ARRAY */
-#ifdef CONFIG_BIGNUM
{ JS_ATOM_BigInt64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_BIG_INT64_ARRAY */
{ JS_ATOM_BigUint64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_BIG_UINT64_ARRAY */
-#endif
{ JS_ATOM_Float32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT32_ARRAY */
{ JS_ATOM_Float64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT64_ARRAY */
{ JS_ATOM_DataView, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_DATAVIEW */
-#ifdef CONFIG_BIGNUM
{ JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_INT */
+#ifdef CONFIG_BIGNUM
{ JS_ATOM_BigFloat, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_FLOAT */
{ JS_ATOM_BigFloatEnv, js_float_env_finalizer, NULL }, /* JS_CLASS_FLOAT_ENV */
{ JS_ATOM_BigDecimal, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_DECIMAL */
@@ -1550,7 +1579,6 @@ static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab,
return 0;
}
-#ifdef CONFIG_BIGNUM
static JSValue JS_ThrowUnsupportedOperation(JSContext *ctx)
{
return JS_ThrowTypeError(ctx, "unsupported operation");
@@ -1606,8 +1634,6 @@ static void set_dummy_numeric_ops(JSNumericOperations *ops)
ops->mul_pow10 = invalid_mul_pow10;
}
-#endif /* CONFIG_BIGNUM */
-
#if !defined(CONFIG_STACK_CHECK)
/* no stack limitation */
static inline uintptr_t js_get_stack_pointer(void)
@@ -1672,9 +1698,9 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
rt->malloc_state = ms;
rt->malloc_gc_threshold = 256 * 1024;
-#ifdef CONFIG_BIGNUM
bf_context_init(&rt->bf_ctx, js_bf_realloc, rt);
set_dummy_numeric_ops(&rt->bigint_ops);
+#ifdef CONFIG_BIGNUM
set_dummy_numeric_ops(&rt->bigfloat_ops);
set_dummy_numeric_ops(&rt->bigdecimal_ops);
#endif
@@ -1729,19 +1755,19 @@ void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque)
}
/* default memory allocation functions with memory limitation */
-static inline size_t js_def_malloc_usable_size(void *ptr)
+static size_t js_def_malloc_usable_size(const void *ptr)
{
#if defined(__APPLE__)
return malloc_size(ptr);
#elif defined(_WIN32)
- return _msize(ptr);
+ return _msize((void *)ptr);
#elif defined(EMSCRIPTEN)
return 0;
#elif defined(__linux__)
- return malloc_usable_size(ptr);
+ return malloc_usable_size((void *)ptr);
#else
/* change this to `return 0;` if compilation fails */
- return malloc_usable_size(ptr);
+ return malloc_usable_size((void *)ptr);
#endif
}
@@ -1805,18 +1831,7 @@ static const JSMallocFunctions def_malloc_funcs = {
js_def_malloc,
js_def_free,
js_def_realloc,
-#if defined(__APPLE__)
- malloc_size,
-#elif defined(_WIN32)
- (size_t (*)(const void *))_msize,
-#elif defined(EMSCRIPTEN)
- NULL,
-#elif defined(__linux__)
- (size_t (*)(const void *))malloc_usable_size,
-#else
- /* change this to `NULL,` if compilation fails */
- malloc_usable_size,
-#endif
+ js_def_malloc_usable_size,
};
JSRuntime *JS_NewRuntime(void)
@@ -2047,9 +2062,7 @@ void JS_FreeRuntime(JSRuntime *rt)
}
js_free_rt(rt, rt->class_array);
-#ifdef CONFIG_BIGNUM
bf_context_end(&rt->bf_ctx);
-#endif
#ifdef DUMP_LEAKS
/* only the atoms defined in JS_InitAtoms() should be left */
@@ -2187,8 +2200,8 @@ JSContext *JS_NewContextRaw(JSRuntime *rt)
}
ctx->rt = rt;
list_add_tail(&ctx->link, &rt->context_list);
-#ifdef CONFIG_BIGNUM
ctx->bf_ctx = &rt->bf_ctx;
+#ifdef CONFIG_BIGNUM
ctx->fp_env.prec = 113;
ctx->fp_env.flags = bf_set_exp_bits(15) | BF_RNDN | BF_FLAG_SUBNORMAL;
#endif
@@ -2221,9 +2234,7 @@ JSContext *JS_NewContext(JSRuntime *rt)
JS_AddIntrinsicMapSet(ctx);
JS_AddIntrinsicTypedArrays(ctx);
JS_AddIntrinsicPromise(ctx);
-#ifdef CONFIG_BIGNUM
JS_AddIntrinsicBigInt(ctx);
-#endif
return ctx;
}
@@ -2264,7 +2275,6 @@ JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id)
typedef enum JSFreeModuleEnum {
JS_FREE_MODULE_ALL,
JS_FREE_MODULE_NOT_RESOLVED,
- JS_FREE_MODULE_NOT_EVALUATED,
} JSFreeModuleEnum;
/* XXX: would be more efficient with separate module lists */
@@ -2274,8 +2284,7 @@ static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag)
list_for_each_safe(el, el1, &ctx->loaded_modules) {
JSModuleDef *m = list_entry(el, JSModuleDef, link);
if (flag == JS_FREE_MODULE_ALL ||
- (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved) ||
- (flag == JS_FREE_MODULE_NOT_EVALUATED && !m->evaluated)) {
+ (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved)) {
js_free_module_def(ctx, m);
}
}
@@ -2431,6 +2440,11 @@ static inline BOOL is_math_mode(JSContext *ctx)
JSStackFrame *sf = ctx->rt->current_stack_frame;
return (sf && (sf->js_mode & JS_MODE_MATH));
}
+#else
+static inline BOOL is_math_mode(JSContext *ctx)
+{
+ return FALSE;
+}
#endif
/* JSAtom support */
@@ -2442,7 +2456,7 @@ static inline BOOL is_math_mode(JSContext *ctx)
/* return the max count from the hash size */
#define JS_ATOM_COUNT_RESIZE(n) ((n) * 2)
-static inline BOOL JS_AtomIsConst(JSAtom v)
+static inline BOOL __JS_AtomIsConst(JSAtom v)
{
#if defined(DUMP_LEAKS) && DUMP_LEAKS > 1
return (int32_t)v <= 0;
@@ -2451,17 +2465,17 @@ static inline BOOL JS_AtomIsConst(JSAtom v)
#endif
}
-static inline BOOL JS_AtomIsTaggedInt(JSAtom v)
+static inline BOOL __JS_AtomIsTaggedInt(JSAtom v)
{
return (v & JS_ATOM_TAG_INT) != 0;
}
-static inline JSAtom JS_AtomFromUInt32(uint32_t v)
+static inline JSAtom __JS_AtomFromUInt32(uint32_t v)
{
return v | JS_ATOM_TAG_INT;
}
-static inline uint32_t JS_AtomToUInt32(JSAtom atom)
+static inline uint32_t __JS_AtomToUInt32(JSAtom atom)
{
return atom & ~JS_ATOM_TAG_INT;
}
@@ -2481,10 +2495,7 @@ static inline BOOL is_num_string(uint32_t *pval, const JSString *p)
len = p->len;
if (len == 0 || len > 10)
return FALSE;
- if (p->is_wide_char)
- c = p->u.str16[0];
- else
- c = p->u.str8[0];
+ c = string_get(p, 0);
if (is_num(c)) {
if (c == '0') {
if (len != 1)
@@ -2493,10 +2504,7 @@ static inline BOOL is_num_string(uint32_t *pval, const JSString *p)
} else {
n = c - '0';
for(i = 1; i < len; i++) {
- if (p->is_wide_char)
- c = p->u.str16[i];
- else
- c = p->u.str8[i];
+ c = string_get(p, i);
if (!is_num(c))
return FALSE;
n64 = (uint64_t)n * 10 + (c - '0');
@@ -2541,10 +2549,24 @@ static uint32_t hash_string(const JSString *str, uint32_t h)
return h;
}
-static maybe_unused void JS_DumpString(JSRuntime *rt,
- const JSString *p)
+static __maybe_unused void JS_DumpChar(JSRuntime *rt, int c, int sep)
+{
+ if (c == sep || c == '\\') {
+ putchar('\\');
+ putchar(c);
+ } else if (c >= ' ' && c <= 126) {
+ putchar(c);
+ } else if (c == '\n') {
+ putchar('\\');
+ putchar('n');
+ } else {
+ printf("\\u%04x", c);
+ }
+}
+
+static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p)
{
- int i, c, sep;
+ int i, sep;
if (p == NULL) {
printf("<null>");
@@ -2554,26 +2576,12 @@ static maybe_unused void JS_DumpString(JSRuntime *rt,
sep = (p->header.ref_count == 1) ? '\"' : '\'';
putchar(sep);
for(i = 0; i < p->len; i++) {
- if (p->is_wide_char)
- c = p->u.str16[i];
- else
- c = p->u.str8[i];
- if (c == sep || c == '\\') {
- putchar('\\');
- putchar(c);
- } else if (c >= ' ' && c <= 126) {
- putchar(c);
- } else if (c == '\n') {
- putchar('\\');
- putchar('n');
- } else {
- printf("\\u%04x", c);
- }
+ JS_DumpChar(rt, string_get(p, i), sep);
}
putchar(sep);
}
-static maybe_unused void JS_DumpAtoms(JSRuntime *rt)
+static __maybe_unused void JS_DumpAtoms(JSRuntime *rt)
{
JSAtomStruct *p;
int h, i;
@@ -2660,7 +2668,7 @@ static int JS_InitAtoms(JSRuntime *rt)
else
atom_type = JS_ATOM_TYPE_STRING;
len = strlen(p);
- if (JS_NewAtomInitImpl(rt, p, len, atom_type) == JS_ATOM_NULL)
+ if (__JS_NewAtomInit(rt, p, len, atom_type) == JS_ATOM_NULL)
return -1;
p = p + len + 1;
}
@@ -2671,7 +2679,7 @@ static JSAtom JS_DupAtomRT(JSRuntime *rt, JSAtom v)
{
JSAtomStruct *p;
- if (!JS_AtomIsConst(v)) {
+ if (!__JS_AtomIsConst(v)) {
p = rt->atom_array[v];
p->header.ref_count++;
}
@@ -2683,7 +2691,7 @@ JSAtom JS_DupAtom(JSContext *ctx, JSAtom v)
JSRuntime *rt;
JSAtomStruct *p;
- if (!JS_AtomIsConst(v)) {
+ if (!__JS_AtomIsConst(v)) {
rt = ctx->rt;
p = rt->atom_array[v];
p->header.ref_count++;
@@ -2697,7 +2705,7 @@ static JSAtomKindEnum JS_AtomGetKind(JSContext *ctx, JSAtom v)
JSAtomStruct *p;
rt = ctx->rt;
- if (JS_AtomIsTaggedInt(v))
+ if (__JS_AtomIsTaggedInt(v))
return JS_ATOM_KIND_STRING;
p = rt->atom_array[v];
switch(p->atom_type) {
@@ -2743,7 +2751,7 @@ static JSAtom js_get_atom_index(JSRuntime *rt, JSAtomStruct *p)
/* string case (internal). Return JS_ATOM_NULL if error. 'str' is
freed. */
-static JSAtom JS_NewAtomImpl(JSRuntime *rt, JSString *str, int atom_type)
+static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type)
{
uint32_t h, h1, i;
JSAtomStruct *p;
@@ -2758,7 +2766,7 @@ static JSAtom JS_NewAtomImpl(JSRuntime *rt, JSString *str, int atom_type)
/* str is the atom, return its index */
i = js_get_atom_index(rt, str);
/* reduce string refcount and increase atom's unless constant */
- if (JS_AtomIsConst(i))
+ if (__JS_AtomIsConst(i))
str->header.ref_count--;
return i;
}
@@ -2774,7 +2782,7 @@ static JSAtom JS_NewAtomImpl(JSRuntime *rt, JSString *str, int atom_type)
p->atom_type == atom_type &&
p->len == len &&
js_string_memcmp(p, str, len) == 0) {
- if (!JS_AtomIsConst(i))
+ if (!__JS_AtomIsConst(i))
p->header.ref_count++;
goto done;
}
@@ -2899,8 +2907,8 @@ static JSAtom JS_NewAtomImpl(JSRuntime *rt, JSString *str, int atom_type)
}
/* only works with zero terminated 8 bit strings */
-static JSAtom JS_NewAtomInitImpl(JSRuntime *rt, const char *str, int len,
- int atom_type)
+static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
+ int atom_type)
{
JSString *p;
p = js_alloc_string_rt(rt, len, 0);
@@ -2908,10 +2916,11 @@ static JSAtom JS_NewAtomInitImpl(JSRuntime *rt, const char *str, int len,
return JS_ATOM_NULL;
memcpy(p->u.str8, str, len);
p->u.str8[len] = '\0';
- return JS_NewAtomImpl(rt, p, atom_type);
+ return __JS_NewAtom(rt, p, atom_type);
}
-static JSAtom JS_FindAtom(JSRuntime *rt, const char *str, size_t len,
+/* Warning: str must be ASCII only */
+static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len,
int atom_type)
{
uint32_t h, h1, i;
@@ -2928,7 +2937,7 @@ static JSAtom JS_FindAtom(JSRuntime *rt, const char *str, size_t len,
p->len == len &&
p->is_wide_char == 0 &&
memcmp(p->u.str8, str, len) == 0) {
- if (!JS_AtomIsConst(i))
+ if (!__JS_AtomIsConst(i))
p->header.ref_count++;
return i;
}
@@ -2980,7 +2989,7 @@ static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p)
assert(rt->atom_count >= 0);
}
-static void JS_FreeAtomImpl(JSRuntime *rt, uint32_t i)
+static void __JS_FreeAtom(JSRuntime *rt, uint32_t i)
{
JSAtomStruct *p;
@@ -2998,19 +3007,21 @@ static JSAtom JS_NewAtomStr(JSContext *ctx, JSString *p)
if (is_num_string(&n, p)) {
if (n <= JS_ATOM_MAX_INT) {
js_free_string(rt, p);
- return JS_AtomFromUInt32(n);
+ return __JS_AtomFromUInt32(n);
}
}
/* XXX: should generate an exception */
- return JS_NewAtomImpl(rt, p, JS_ATOM_TYPE_STRING);
+ return __JS_NewAtom(rt, p, JS_ATOM_TYPE_STRING);
}
+/* str is UTF-8 encoded */
JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len)
{
JSValue val;
if (len == 0 || !is_digit(*str)) {
- JSAtom atom = JS_FindAtom(ctx->rt, str, len, JS_ATOM_TYPE_STRING);
+ // XXX: this will not work if UTF-8 encoded str contains non ASCII bytes
+ JSAtom atom = __JS_FindAtom(ctx->rt, str, len, JS_ATOM_TYPE_STRING);
if (atom)
return atom;
}
@@ -3028,7 +3039,7 @@ JSAtom JS_NewAtom(JSContext *ctx, const char *str)
JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n)
{
if (n <= JS_ATOM_MAX_INT) {
- return JS_AtomFromUInt32(n);
+ return __JS_AtomFromUInt32(n);
} else {
char buf[11];
JSValue val;
@@ -3036,7 +3047,7 @@ JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n)
val = JS_NewString(ctx, buf);
if (JS_IsException(val))
return JS_ATOM_NULL;
- return JS_NewAtomImpl(ctx->rt, JS_VALUE_GET_STRING(val),
+ return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
JS_ATOM_TYPE_STRING);
}
}
@@ -3044,7 +3055,7 @@ JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n)
static JSAtom JS_NewAtomInt64(JSContext *ctx, int64_t n)
{
if ((uint64_t)n <= JS_ATOM_MAX_INT) {
- return JS_AtomFromUInt32((uint32_t)n);
+ return __JS_AtomFromUInt32((uint32_t)n);
} else {
char buf[24];
JSValue val;
@@ -3052,7 +3063,7 @@ static JSAtom JS_NewAtomInt64(JSContext *ctx, int64_t n)
val = JS_NewString(ctx, buf);
if (JS_IsException(val))
return JS_ATOM_NULL;
- return JS_NewAtomImpl(ctx->rt, JS_VALUE_GET_STRING(val),
+ return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
JS_ATOM_TYPE_STRING);
}
}
@@ -3062,7 +3073,7 @@ static JSValue JS_NewSymbol(JSContext *ctx, JSString *p, int atom_type)
{
JSRuntime *rt = ctx->rt;
JSAtom atom;
- atom = JS_NewAtomImpl(rt, p, atom_type);
+ atom = __JS_NewAtom(rt, p, atom_type);
if (atom == JS_ATOM_NULL)
return JS_ThrowOutOfMemory(ctx);
return JS_MKPTR(JS_TAG_SYMBOL, rt->atom_array[atom]);
@@ -3075,7 +3086,7 @@ static JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr,
JSRuntime *rt = ctx->rt;
JSString *p;
- assert(!JS_AtomIsTaggedInt(descr));
+ assert(!__JS_AtomIsTaggedInt(descr));
assert(descr < rt->atom_size);
p = rt->atom_array[descr];
JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
@@ -3088,8 +3099,8 @@ static JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr,
static const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size,
JSAtom atom)
{
- if (JS_AtomIsTaggedInt(atom)) {
- snprintf(buf, buf_size, "%u", JS_AtomToUInt32(atom));
+ if (__JS_AtomIsTaggedInt(atom)) {
+ snprintf(buf, buf_size, "%u", __JS_AtomToUInt32(atom));
} else {
JSAtomStruct *p;
assert(atom < rt->atom_size);
@@ -3115,10 +3126,7 @@ static const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size,
return (const char *)str->u.str8;
}
for(i = 0; i < str->len; i++) {
- if (str->is_wide_char)
- c = str->u.str16[i];
- else
- c = str->u.str8[i];
+ c = string_get(str, i);
if ((q - buf) >= buf_size - UTF8_CHAR_LEN_MAX)
break;
if (c < 128) {
@@ -3139,12 +3147,12 @@ static const char *JS_AtomGetStr(JSContext *ctx, char *buf, int buf_size, JSAtom
return JS_AtomGetStrRT(ctx->rt, buf, buf_size, atom);
}
-static JSValue JS_AtomToValueImpl(JSContext *ctx, JSAtom atom, BOOL force_string)
+static JSValue __JS_AtomToValue(JSContext *ctx, JSAtom atom, BOOL force_string)
{
char buf[ATOM_GET_STR_BUF_SIZE];
- if (JS_AtomIsTaggedInt(atom)) {
- snprintf(buf, sizeof(buf), "%u", JS_AtomToUInt32(atom));
+ if (__JS_AtomIsTaggedInt(atom)) {
+ snprintf(buf, sizeof(buf), "%u", __JS_AtomToUInt32(atom));
return JS_NewString(ctx, buf);
} else {
JSRuntime *rt = ctx->rt;
@@ -3168,20 +3176,20 @@ static JSValue JS_AtomToValueImpl(JSContext *ctx, JSAtom atom, BOOL force_string
JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom)
{
- return JS_AtomToValueImpl(ctx, atom, FALSE);
+ return __JS_AtomToValue(ctx, atom, FALSE);
}
JSValue JS_AtomToString(JSContext *ctx, JSAtom atom)
{
- return JS_AtomToValueImpl(ctx, atom, TRUE);
+ return __JS_AtomToValue(ctx, atom, TRUE);
}
/* return TRUE if the atom is an array index (i.e. 0 <= index <=
2^32-2 and return its value */
static BOOL JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom)
{
- if (JS_AtomIsTaggedInt(atom)) {
- *pval = JS_AtomToUInt32(atom);
+ if (__JS_AtomIsTaggedInt(atom)) {
+ *pval = __JS_AtomToUInt32(atom);
return TRUE;
} else {
JSRuntime *rt = ctx->rt;
@@ -3212,8 +3220,8 @@ static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom)
int c, len, ret;
JSValue num, str;
- if (JS_AtomIsTaggedInt(atom))
- return JS_NewInt32(ctx, JS_AtomToUInt32(atom));
+ if (__JS_AtomIsTaggedInt(atom))
+ return JS_NewInt32(ctx, __JS_AtomToUInt32(atom));
assert(atom < rt->atom_size);
p1 = rt->atom_array[atom];
if (p1->atom_type != JS_ATOM_TYPE_STRING)
@@ -3255,7 +3263,7 @@ static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom)
/* -0 case is specific */
if (c == '0' && len == 2) {
minus_zero:
- return JS_NewFloat64Impl(ctx, -0.0);
+ return __JS_NewFloat64(ctx, -0.0);
}
}
if (!is_num(c)) {
@@ -3300,14 +3308,14 @@ static int JS_AtomIsNumericIndex(JSContext *ctx, JSAtom atom)
void JS_FreeAtom(JSContext *ctx, JSAtom v)
{
- if (!JS_AtomIsConst(v))
- JS_FreeAtomImpl(ctx->rt, v);
+ if (!__JS_AtomIsConst(v))
+ __JS_FreeAtom(ctx->rt, v);
}
void JS_FreeAtomRT(JSRuntime *rt, JSAtom v)
{
- if (!JS_AtomIsConst(v))
- JS_FreeAtomImpl(rt, v);
+ if (!__JS_AtomIsConst(v))
+ __JS_FreeAtom(rt, v);
}
/* return TRUE if 'v' is a symbol with a string description */
@@ -3317,7 +3325,7 @@ static BOOL JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v)
JSAtomStruct *p;
rt = ctx->rt;
- if (JS_AtomIsTaggedInt(v))
+ if (__JS_AtomIsTaggedInt(v))
return FALSE;
p = rt->atom_array[v];
return (((p->atom_type == JS_ATOM_TYPE_SYMBOL &&
@@ -3326,7 +3334,7 @@ static BOOL JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v)
!(p->len == 0 && p->is_wide_char != 0));
}
-static maybe_unused void print_atom(JSContext *ctx, JSAtom atom)
+static __maybe_unused void print_atom(JSContext *ctx, JSAtom atom)
{
char buf[ATOM_GET_STR_BUF_SIZE];
const char *p;
@@ -3425,19 +3433,37 @@ static inline BOOL JS_IsEmptyString(JSValueConst v)
/* JSClass support */
+#ifdef CONFIG_ATOMICS
+static pthread_mutex_t js_class_id_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
/* a new class ID is allocated if *pclass_id != 0 */
JSClassID JS_NewClassID(JSClassID *pclass_id)
{
JSClassID class_id;
- /* XXX: make it thread safe */
+#ifdef CONFIG_ATOMICS
+ pthread_mutex_lock(&js_class_id_mutex);
+#endif
class_id = *pclass_id;
if (class_id == 0) {
class_id = js_class_id_alloc++;
*pclass_id = class_id;
}
+#ifdef CONFIG_ATOMICS
+ pthread_mutex_unlock(&js_class_id_mutex);
+#endif
return class_id;
}
+JSClassID JS_GetClassID(JSValue v)
+{
+ JSObject *p;
+ if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT)
+ return JS_INVALID_CLASS_ID;
+ p = JS_VALUE_GET_OBJ(v);
+ return p->class_id;
+}
+
BOOL JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id)
{
return (class_id < rt->class_count &&
@@ -3501,9 +3527,9 @@ int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def)
JSAtom name;
len = strlen(class_def->class_name);
- name = JS_FindAtom(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
+ name = __JS_FindAtom(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
if (name == JS_ATOM_NULL) {
- name = JS_NewAtomInitImpl(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
+ name = __JS_NewAtomInit(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
if (name == JS_ATOM_NULL)
return -1;
}
@@ -3732,28 +3758,23 @@ static int string_buffer_putc(StringBuffer *s, uint32_t c)
{
if (unlikely(c >= 0x10000)) {
/* surrogate pair */
- c -= 0x10000;
- if (string_buffer_putc16(s, (c >> 10) + 0xd800))
+ if (string_buffer_putc16(s, get_hi_surrogate(c)))
return -1;
- c = (c & 0x3ff) + 0xdc00;
+ c = get_lo_surrogate(c);
}
return string_buffer_putc16(s, c);
}
-static int string_get(const JSString *p, int idx) {
- return p->is_wide_char ? p->u.str16[idx] : p->u.str8[idx];
-}
-
static int string_getc(const JSString *p, int *pidx)
{
int idx, c, c1;
idx = *pidx;
if (p->is_wide_char) {
c = p->u.str16[idx++];
- if (c >= 0xd800 && c < 0xdc00 && idx < p->len) {
+ if (is_hi_surrogate(c) && idx < p->len) {
c1 = p->u.str16[idx];
- if (c1 >= 0xdc00 && c1 < 0xe000) {
- c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
+ if (is_lo_surrogate(c1)) {
+ c = from_surrogate(c, c1);
idx++;
}
}
@@ -3951,9 +3972,8 @@ JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len)
} else if (c <= 0x10FFFF) {
p = p_next;
/* surrogate pair */
- c -= 0x10000;
- string_buffer_putc16(b, (c >> 10) + 0xd800);
- c = (c & 0x3ff) + 0xdc00;
+ string_buffer_putc16(b, get_hi_surrogate(c));
+ c = get_lo_surrogate(c);
} else {
/* invalid char */
c = 0xfffd;
@@ -4091,13 +4111,12 @@ const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, BO
if (c < 0x80) {
*q++ = c;
} else {
- if (c >= 0xd800 && c < 0xdc00) {
+ if (is_hi_surrogate(c)) {
if (pos < len && !cesu8) {
c1 = src[pos];
- if (c1 >= 0xdc00 && c1 < 0xe000) {
+ if (is_lo_surrogate(c1)) {
pos++;
- /* surrogate pair */
- c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
+ c = from_surrogate(c, c1);
} else {
/* Keep unmatched surrogate code points */
/* c = 0xfffd; */ /* error */
@@ -4130,7 +4149,7 @@ void JS_FreeCString(JSContext *ctx, const char *ptr)
if (!ptr)
return;
/* purposely removing constness */
- p = (JSString *)(void *)(ptr - offsetof(JSString, u));
+ p = container_of(ptr, JSString, u);
JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
}
@@ -4230,7 +4249,43 @@ static JSValue JS_ConcatString1(JSContext *ctx,
return JS_MKPTR(JS_TAG_STRING, p);
}
-/* op1 and op2 are converted to strings. For convience, op1 or op2 =
+static BOOL JS_ConcatStringInPlace(JSContext *ctx, JSString *p1, JSValueConst op2) {
+ if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {
+ JSString *p2 = JS_VALUE_GET_STRING(op2);
+ size_t size1;
+
+ if (p2->len == 0)
+ return TRUE;
+ if (p1->header.ref_count != 1)
+ return FALSE;
+ size1 = js_malloc_usable_size(ctx, p1);
+ if (p1->is_wide_char) {
+ if (size1 >= sizeof(*p1) + ((p1->len + p2->len) << 1)) {
+ if (p2->is_wide_char) {
+ memcpy(p1->u.str16 + p1->len, p2->u.str16, p2->len << 1);
+ p1->len += p2->len;
+ return TRUE;
+ } else {
+ size_t i;
+ for (i = 0; i < p2->len; i++) {
+ p1->u.str16[p1->len++] = p2->u.str8[i];
+ }
+ return TRUE;
+ }
+ }
+ } else if (!p2->is_wide_char) {
+ if (size1 >= sizeof(*p1) + p1->len + p2->len + 1) {
+ memcpy(p1->u.str8 + p1->len, p2->u.str8, p2->len);
+ p1->len += p2->len;
+ p1->u.str8[p1->len] = '\0';
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/* op1 and op2 are converted to strings. For convenience, op1 or op2 =
JS_EXCEPTION are accepted and return JS_EXCEPTION. */
static JSValue JS_ConcatString(JSContext *ctx, JSValue op1, JSValue op2)
{
@@ -4252,27 +4307,11 @@ static JSValue JS_ConcatString(JSContext *ctx, JSValue op1, JSValue op2)
}
}
p1 = JS_VALUE_GET_STRING(op1);
- p2 = JS_VALUE_GET_STRING(op2);
-
- /* XXX: could also check if p1 is empty */
- if (p2->len == 0) {
- goto ret_op1;
- }
- if (p1->header.ref_count == 1 && p1->is_wide_char == p2->is_wide_char
- && js_malloc_usable_size(ctx, p1) >= sizeof(*p1) + ((p1->len + p2->len) << p2->is_wide_char) + 1 - p1->is_wide_char) {
- /* Concatenate in place in available space at the end of p1 */
- if (p1->is_wide_char) {
- memcpy(p1->u.str16 + p1->len, p2->u.str16, p2->len << 1);
- p1->len += p2->len;
- } else {
- memcpy(p1->u.str8 + p1->len, p2->u.str8, p2->len);
- p1->len += p2->len;
- p1->u.str8[p1->len] = '\0';
- }
- ret_op1:
+ if (JS_ConcatStringInPlace(ctx, p1, op2)) {
JS_FreeValue(ctx, op2);
return op1;
}
+ p2 = JS_VALUE_GET_STRING(op2);
ret = JS_ConcatString1(ctx, p1, p2);
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
@@ -4509,6 +4548,7 @@ static no_inline int resize_properties(JSContext *ctx, JSShape **psh,
JSShapeProperty *pr;
void *sh_alloc;
intptr_t h;
+ JSShape *old_sh;
sh = *psh;
new_size = max_int(count, sh->prop_size * 3 / 2);
@@ -4524,19 +4564,21 @@ static no_inline int resize_properties(JSContext *ctx, JSShape **psh,
new_hash_size = sh->prop_hash_mask + 1;
while (new_hash_size < new_size)
new_hash_size = 2 * new_hash_size;
+ /* resize the property shapes. Using js_realloc() is not possible in
+ case the GC runs during the allocation */
+ old_sh = sh;
+ sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
+ if (!sh_alloc)
+ return -1;
+ sh = get_shape_from_alloc(sh_alloc, new_hash_size);
+ list_del(&old_sh->header.link);
+ /* copy all the shape properties */
+ memcpy(sh, old_sh,
+ sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count);
+ list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
+
if (new_hash_size != (sh->prop_hash_mask + 1)) {
- JSShape *old_sh;
/* resize the hash table and the properties */
- old_sh = sh;
- sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
- if (!sh_alloc)
- return -1;
- sh = get_shape_from_alloc(sh_alloc, new_hash_size);
- list_del(&old_sh->header.link);
- /* copy all the fields and the properties */
- memcpy(sh, old_sh,
- sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count);
- list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
new_hash_mask = new_hash_size - 1;
sh->prop_hash_mask = new_hash_mask;
memset(prop_hash_end(sh) - new_hash_size, 0,
@@ -4548,20 +4590,12 @@ static no_inline int resize_properties(JSContext *ctx, JSShape **psh,
prop_hash_end(sh)[-h - 1] = i + 1;
}
}
- js_free(ctx, get_alloc_from_shape(old_sh));
} else {
- /* only resize the properties */
- list_del(&sh->header.link);
- sh_alloc = js_realloc(ctx, get_alloc_from_shape(sh),
- get_shape_size(new_hash_size, new_size));
- if (unlikely(!sh_alloc)) {
- /* insert again in the GC list */
- list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
- return -1;
- }
- sh = get_shape_from_alloc(sh_alloc, new_hash_size);
- list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
+ /* just copy the previous hash table */
+ memcpy(prop_hash_end(sh) - new_hash_size, prop_hash_end(old_sh) - new_hash_size,
+ sizeof(prop_hash_end(sh)[0]) * new_hash_size);
}
+ js_free(ctx, get_alloc_from_shape(old_sh));
*psh = sh;
sh->prop_size = new_size;
return 0;
@@ -4670,7 +4704,7 @@ static int add_shape_property(JSContext *ctx, JSShape **psh,
pr = &prop[sh->prop_count++];
pr->atom = JS_DupAtom(ctx, atom);
pr->flags = prop_flags;
- sh->has_small_array_index |= JS_AtomIsTaggedInt(atom);
+ sh->has_small_array_index |= __JS_AtomIsTaggedInt(atom);
/* add in hash table */
hash_mask = sh->prop_hash_mask;
h = atom & hash_mask;
@@ -4731,7 +4765,7 @@ static JSShape *find_hashed_shape_prop(JSRuntime *rt, JSShape *sh,
return NULL;
}
-static maybe_unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh)
+static __maybe_unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh)
{
char atom_buf[ATOM_GET_STR_BUF_SIZE];
int j;
@@ -4747,7 +4781,7 @@ static maybe_unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh)
printf("\n");
}
-static maybe_unused void JS_DumpShapes(JSRuntime *rt)
+static __maybe_unused void JS_DumpShapes(JSRuntime *rt)
{
int i;
JSShape *sh;
@@ -4838,10 +4872,8 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas
case JS_CLASS_UINT16_ARRAY:
case JS_CLASS_INT32_ARRAY:
case JS_CLASS_UINT32_ARRAY:
-#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT64_ARRAY:
case JS_CLASS_BIG_UINT64_ARRAY:
-#endif
case JS_CLASS_FLOAT32_ARRAY:
case JS_CLASS_FLOAT64_ARRAY:
p->is_exotic = 1;
@@ -4858,8 +4890,8 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas
case JS_CLASS_BOOLEAN:
case JS_CLASS_SYMBOL:
case JS_CLASS_DATE:
-#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT:
+#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_FLOAT:
case JS_CLASS_BIG_DECIMAL:
#endif
@@ -4921,8 +4953,8 @@ static JSValue JS_GetObjectData(JSContext *ctx, JSValueConst obj)
case JS_CLASS_BOOLEAN:
case JS_CLASS_SYMBOL:
case JS_CLASS_DATE:
-#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT:
+#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_FLOAT:
case JS_CLASS_BIG_DECIMAL:
#endif
@@ -4945,8 +4977,8 @@ static int JS_SetObjectData(JSContext *ctx, JSValueConst obj, JSValue val)
case JS_CLASS_BOOLEAN:
case JS_CLASS_SYMBOL:
case JS_CLASS_DATE:
-#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT:
+#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_FLOAT:
case JS_CLASS_BIG_DECIMAL:
#endif
@@ -5293,10 +5325,12 @@ static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref)
if (--var_ref->header.ref_count == 0) {
if (var_ref->is_detached) {
JS_FreeValueRT(rt, var_ref->value);
- remove_gc_object(&var_ref->header);
} else {
- list_del(&var_ref->header.link); /* still on the stack */
+ list_del(&var_ref->var_ref_link); /* still on the stack */
+ if (var_ref->async_func)
+ async_func_free(rt, var_ref->async_func);
}
+ remove_gc_object(&var_ref->header);
js_free_rt(rt, var_ref);
}
}
@@ -5394,7 +5428,7 @@ static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
if (var_refs) {
for(i = 0; i < b->closure_var_count; i++) {
JSVarRef *var_ref = var_refs[i];
- if (var_ref && var_ref->is_detached) {
+ if (var_ref) {
mark_func(rt, &var_ref->header);
}
}
@@ -5436,7 +5470,15 @@ static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val)
{
JSObject *p = JS_VALUE_GET_OBJ(val);
JSForInIterator *it = p->u.for_in_iterator;
+ int i;
+
JS_FreeValueRT(rt, it->obj);
+ if (!it->is_array) {
+ for(i = 0; i < it->atom_count; i++) {
+ JS_FreeAtomRT(rt, it->tab_atom[i].atom);
+ }
+ js_free_rt(rt, it->tab_atom);
+ }
js_free_rt(rt, it);
}
@@ -5504,6 +5546,9 @@ static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp)
case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
free_function_bytecode(rt, (JSFunctionBytecode *)gp);
break;
+ case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
+ __async_func_free(rt, (JSAsyncFunctionState *)gp);
+ break;
default:
abort();
}
@@ -5527,7 +5572,7 @@ static void free_zero_refcount(JSRuntime *rt)
}
/* called with the ref_count of 'v' reaches zero. */
-static void JS_FreeValueRTImpl(JSRuntime *rt, JSValue v)
+static void __JS_FreeValueRT(JSRuntime *rt, JSValue v)
{
uint32_t tag = JS_VALUE_GET_TAG(v);
@@ -5573,15 +5618,17 @@ static void JS_FreeValueRTImpl(JSRuntime *rt, JSValue v)
case JS_TAG_MODULE:
abort(); /* never freed here */
break;
-#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
+#endif
{
JSBigFloat *bf = JS_VALUE_GET_PTR(v);
bf_delete(&bf->num);
js_free_rt(rt, bf);
}
break;
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_DECIMAL:
{
JSBigDecimal *bf = JS_VALUE_GET_PTR(v);
@@ -5602,9 +5649,9 @@ static void JS_FreeValueRTImpl(JSRuntime *rt, JSValue v)
}
}
-static void JS_FreeValueImpl(JSContext *ctx, JSValue v)
+static void __JS_FreeValue(JSContext *ctx, JSValue v)
{
- JS_FreeValueRTImpl(ctx->rt, v);
+ __JS_FreeValueRT(ctx->rt, v);
}
/* garbage collection */
@@ -5660,11 +5707,9 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,
if (pr->u.getset.setter)
mark_func(rt, &pr->u.getset.setter->header);
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
- if (pr->u.var_ref->is_detached) {
- /* Note: the tag does not matter
- provided it is a GC object */
- mark_func(rt, &pr->u.var_ref->header);
- }
+ /* Note: the tag does not matter
+ provided it is a GC object */
+ mark_func(rt, &pr->u.var_ref->header);
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
js_autoinit_mark(rt, pr, mark_func);
}
@@ -5698,16 +5743,32 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,
case JS_GC_OBJ_TYPE_VAR_REF:
{
JSVarRef *var_ref = (JSVarRef *)gp;
- /* only detached variable referenced are taken into account */
- assert(var_ref->is_detached);
- JS_MarkValue(rt, *var_ref->pvalue, mark_func);
+ if (var_ref->is_detached) {
+ JS_MarkValue(rt, *var_ref->pvalue, mark_func);
+ } else if (var_ref->async_func) {
+ mark_func(rt, &var_ref->async_func->header);
+ }
}
break;
case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
{
- JSAsyncFunctionData *s = (JSAsyncFunctionData *)gp;
- if (s->is_active)
- async_func_mark(rt, &s->func_state, mark_func);
+ JSAsyncFunctionState *s = (JSAsyncFunctionState *)gp;
+ JSStackFrame *sf = &s->frame;
+ JSValue *sp;
+
+ if (!s->is_completed) {
+ JS_MarkValue(rt, sf->cur_func, mark_func);
+ JS_MarkValue(rt, s->this_val, mark_func);
+ /* sf->cur_sp = NULL if the function is running */
+ if (sf->cur_sp) {
+ /* if the function is running, cur_sp is not known so we
+ cannot mark the stack. Marking the variables is not needed
+ because a running function cannot be part of a removable
+ cycle */
+ for(sp = sf->arg_buf; sp < sf->cur_sp; sp++)
+ JS_MarkValue(rt, *sp, mark_func);
+ }
+ }
JS_MarkValue(rt, s->resolving_funcs[0], mark_func);
JS_MarkValue(rt, s->resolving_funcs[1], mark_func);
}
@@ -5815,12 +5876,13 @@ static void gc_free_cycles(JSRuntime *rt)
if (el == &rt->tmp_obj_list)
break;
p = list_entry(el, JSGCObjectHeader, link);
- /* Only need to free the GC object associated with JS
- values. The rest will be automatically removed because they
- must be referenced by them. */
+ /* Only need to free the GC object associated with JS values
+ or async functions. The rest will be automatically removed
+ because they must be referenced by them. */
switch(p->gc_obj_type) {
case JS_GC_OBJ_TYPE_JS_OBJECT:
case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
+ case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
#ifdef DUMP_GC_FREE
if (!header_done) {
printf("Freeing cycles:\n");
@@ -5842,7 +5904,8 @@ static void gc_free_cycles(JSRuntime *rt)
list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) {
p = list_entry(el, JSGCObjectHeader, link);
assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT ||
- p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
+ p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE ||
+ p->gc_obj_type == JS_GC_OBJ_TYPE_ASYNC_FUNCTION);
js_free_rt(rt, p);
}
@@ -5944,13 +6007,13 @@ static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp)
case JS_TAG_STRING:
compute_jsstring_size(JS_VALUE_GET_STRING(val), hp);
break;
-#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
case JS_TAG_BIG_DECIMAL:
+#endif
/* should track JSBigFloat usage */
break;
-#endif
}
}
@@ -6074,8 +6137,8 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
case JS_CLASS_BOOLEAN: /* u.object_data */
case JS_CLASS_SYMBOL: /* u.object_data */
case JS_CLASS_DATE: /* u.object_data */
-#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT: /* u.object_data */
+#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_FLOAT: /* u.object_data */
case JS_CLASS_BIG_DECIMAL: /* u.object_data */
#endif
@@ -6167,10 +6230,8 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
case JS_CLASS_UINT16_ARRAY: /* u.typed_array / u.array */
case JS_CLASS_INT32_ARRAY: /* u.typed_array / u.array */
case JS_CLASS_UINT32_ARRAY: /* u.typed_array / u.array */
-#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT64_ARRAY: /* u.typed_array / u.array */
case JS_CLASS_BIG_UINT64_ARRAY: /* u.typed_array / u.array */
-#endif
case JS_CLASS_FLOAT32_ARRAY: /* u.typed_array / u.array */
case JS_CLASS_FLOAT64_ARRAY: /* u.typed_array / u.array */
case JS_CLASS_DATAVIEW: /* u.typed_array */
@@ -6251,7 +6312,7 @@ void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)
"BigNum "
#endif
CONFIG_VERSION " version, %d-bit, malloc limit: %"PRId64"\n\n",
- (int)sizeof(void *) * 8, (int64_t)(ssize_t)s->malloc_limit);
+ (int)sizeof(void *) * 8, s->malloc_limit);
#if 1
if (rt) {
static const struct {
@@ -6297,10 +6358,10 @@ void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)
if (obj_classes[0])
fprintf(fp, " %5d %2.0d %s\n", obj_classes[0], 0, "none");
for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) {
- if (obj_classes[class_id]) {
+ if (obj_classes[class_id] && class_id < rt->class_count) {
char buf[ATOM_GET_STR_BUF_SIZE];
fprintf(fp, " %5d %2.0d %s\n", obj_classes[class_id], class_id,
- JS_AtomGetStrRT(rt, buf, sizeof(buf), js_std_class_def[class_id - 1].class_name));
+ JS_AtomGetStrRT(rt, buf, sizeof(buf), rt->class_array[class_id].class_name));
}
}
if (obj_classes[JS_CLASS_INIT_COUNT])
@@ -6397,6 +6458,11 @@ JSValue JS_GetException(JSContext *ctx)
return val;
}
+JS_BOOL JS_HasException(JSContext *ctx)
+{
+ return !JS_IsNull(ctx->rt->current_exception);
+}
+
static void dbuf_put_leb128(DynBuf *s, uint32_t v)
{
uint32_t a;
@@ -6526,8 +6592,8 @@ static const char *get_func_name(JSContext *ctx, JSValueConst func)
/* if filename != NULL, an additional level is added with the filename
and line number information (used for parse error). */
void build_backtrace(JSContext *ctx, JSValueConst error_obj,
- const char *filename, int line_num,
- int backtrace_flags)
+ const char *filename, int line_num,
+ int backtrace_flags)
{
JSStackFrame *sf;
JSValue str;
@@ -6698,7 +6764,7 @@ static int FORMAT_ATTR(3, 4) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags,
}
/* never use it directly */
-static JSValue FORMAT_ATTR(3, 4) JS_ThrowTypeErrorAtomImpl(JSContext *ctx, JSAtom atom, const char *fmt, ...)
+static JSValue FORMAT_ATTR(3, 4) __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
{
char buf[ATOM_GET_STR_BUF_SIZE];
return JS_ThrowTypeError(ctx, fmt,
@@ -6706,7 +6772,7 @@ static JSValue FORMAT_ATTR(3, 4) JS_ThrowTypeErrorAtomImpl(JSContext *ctx, JSAto
}
/* never use it directly */
-static JSValue FORMAT_ATTR(3, 4) JS_ThrowSyntaxErrorAtomImpl(JSContext *ctx, JSAtom atom, const char *fmt, ...)
+static JSValue FORMAT_ATTR(3, 4) __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
{
char buf[ATOM_GET_STR_BUF_SIZE];
return JS_ThrowSyntaxError(ctx, fmt,
@@ -6715,8 +6781,8 @@ static JSValue FORMAT_ATTR(3, 4) JS_ThrowSyntaxErrorAtomImpl(JSContext *ctx, JSA
/* %s is replaced by 'atom'. The macro is used so that gcc can check
the format string. */
-#define JS_ThrowTypeErrorAtom(ctx, fmt, atom) JS_ThrowTypeErrorAtomImpl(ctx, atom, fmt, "")
-#define JS_ThrowSyntaxErrorAtom(ctx, fmt, atom) JS_ThrowSyntaxErrorAtomImpl(ctx, atom, fmt, "")
+#define JS_ThrowTypeErrorAtom(ctx, fmt, atom) __JS_ThrowTypeErrorAtom(ctx, atom, fmt, "")
+#define JS_ThrowSyntaxErrorAtom(ctx, fmt, atom) __JS_ThrowSyntaxErrorAtom(ctx, atom, fmt, "")
static int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom)
{
@@ -6826,7 +6892,7 @@ static JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id)
return JS_ThrowTypeErrorAtom(ctx, "%s object expected", name);
}
-static no_inline warn_unused int js_poll_interrupts_impl(JSContext *ctx)
+static no_inline __exception int __js_poll_interrupts(JSContext *ctx)
{
JSRuntime *rt = ctx->rt;
ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT;
@@ -6841,10 +6907,10 @@ static no_inline warn_unused int js_poll_interrupts_impl(JSContext *ctx)
return 0;
}
-static inline warn_unused int js_poll_interrupts(JSContext *ctx)
+static inline __exception int js_poll_interrupts(JSContext *ctx)
{
if (unlikely(--ctx->interrupt_counter <= 0)) {
- return js_poll_interrupts_impl(ctx);
+ return __js_poll_interrupts(ctx);
} else {
return 0;
}
@@ -6931,10 +6997,10 @@ int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val)
static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val)
{
switch(JS_VALUE_GET_NORM_TAG(val)) {
-#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
val = ctx->class_proto[JS_CLASS_BIG_INT];
break;
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
val = ctx->class_proto[JS_CLASS_BIG_FLOAT];
break;
@@ -7148,9 +7214,9 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
case JS_TAG_STRING:
{
JSString *p1 = JS_VALUE_GET_STRING(obj);
- if (JS_AtomIsTaggedInt(prop)) {
+ if (__JS_AtomIsTaggedInt(prop)) {
uint32_t idx, ch;
- idx = JS_AtomToUInt32(prop);
+ idx = __JS_AtomToUInt32(prop);
if (idx < p1->len) {
if (p1->is_wide_char)
ch = p1->u.str16[idx];
@@ -7208,8 +7274,8 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
if (unlikely(p->is_exotic)) {
/* exotic behaviors */
if (p->fast_array) {
- if (JS_AtomIsTaggedInt(prop)) {
- uint32_t idx = JS_AtomToUInt32(prop);
+ if (__JS_AtomIsTaggedInt(prop)) {
+ uint32_t idx = __JS_AtomToUInt32(prop);
if (idx < p->u.array.count) {
/* we avoid duplicating the code */
return JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
@@ -7371,6 +7437,8 @@ static int JS_SetPrivateField(JSContext *ctx, JSValueConst obj,
return 0;
}
+/* add a private brand field to 'home_obj' if not already present and
+ if obj is != null add a private brand to it */
static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj)
{
JSObject *p, *p1;
@@ -7386,10 +7454,10 @@ static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj)
p = JS_VALUE_GET_OBJ(home_obj);
prs = find_own_property(&pr, p, JS_ATOM_Private_brand);
if (!prs) {
+ /* if the brand is not present, add it */
brand = JS_NewSymbolFromAtom(ctx, JS_ATOM_brand, JS_ATOM_TYPE_PRIVATE);
if (JS_IsException(brand))
return -1;
- /* if the brand is not present, add it */
pr = add_property(ctx, p, JS_ATOM_Private_brand, JS_PROP_C_W_E);
if (!pr) {
JS_FreeValue(ctx, brand);
@@ -7401,20 +7469,27 @@ static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj)
}
brand_atom = js_symbol_to_atom(ctx, brand);
- if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
- JS_ThrowTypeErrorNotAnObject(ctx);
+ if (JS_IsObject(obj)) {
+ p1 = JS_VALUE_GET_OBJ(obj);
+ prs = find_own_property(&pr, p1, brand_atom);
+ if (unlikely(prs)) {
+ JS_FreeAtom(ctx, brand_atom);
+ JS_ThrowTypeError(ctx, "private method is already present");
+ return -1;
+ }
+ pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E);
+ JS_FreeAtom(ctx, brand_atom);
+ if (!pr)
+ return -1;
+ pr->u.value = JS_UNDEFINED;
+ } else {
JS_FreeAtom(ctx, brand_atom);
- return -1;
}
- p1 = JS_VALUE_GET_OBJ(obj);
- pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E);
- JS_FreeAtom(ctx, brand_atom);
- if (!pr)
- return -1;
- pr->u.value = JS_UNDEFINED;
return 0;
}
+/* return a boolean telling if the brand of the home object of 'func'
+ is present on 'obj' or -1 in case of exception */
static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func)
{
JSObject *p, *p1, *home_obj;
@@ -7423,11 +7498,8 @@ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func)
JSValueConst brand;
/* get the home object of 'func' */
- if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)) {
- not_obj:
- JS_ThrowTypeErrorNotAnObject(ctx);
- return -1;
- }
+ if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT))
+ goto not_obj;
p1 = JS_VALUE_GET_OBJ(func);
if (!js_class_has_bytecode(p1->class_id))
goto not_obj;
@@ -7445,15 +7517,14 @@ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func)
goto not_obj;
/* get the brand array of 'obj' */
- if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
- goto not_obj;
- p = JS_VALUE_GET_OBJ(obj);
- prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, brand));
- if (!prs) {
- JS_ThrowTypeError(ctx, "invalid brand on object");
+ if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
+ not_obj:
+ JS_ThrowTypeErrorNotAnObject(ctx);
return -1;
}
- return 0;
+ p = JS_VALUE_GET_OBJ(obj);
+ prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, brand));
+ return (prs != NULL);
}
static uint32_t js_string_obj_get_length(JSContext *ctx,
@@ -7503,7 +7574,7 @@ static void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len)
/* return < 0 in case if exception, 0 if OK. ptab and its atoms must
be freed by the user. */
-static int warn_unused JS_GetOwnPropertyNamesInternal(JSContext *ctx,
+static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
JSPropertyEnum **ptab,
uint32_t *plen,
JSObject *p, int flags)
@@ -7653,7 +7724,7 @@ static int warn_unused JS_GetOwnPropertyNamesInternal(JSContext *ctx,
len = js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
add_array_keys:
for(i = 0; i < len; i++) {
- tab_atom[num_index].atom = JS_AtomFromUInt32(i);
+ tab_atom[num_index].atom = __JS_AtomFromUInt32(i);
if (tab_atom[num_index].atom == JS_ATOM_NULL) {
js_free_prop_enum(ctx, tab_atom, num_index);
return -1;
@@ -7761,9 +7832,9 @@ retry:
if (p->is_exotic) {
if (p->fast_array) {
/* specific case for fast arrays */
- if (JS_AtomIsTaggedInt(prop)) {
+ if (__JS_AtomIsTaggedInt(prop)) {
uint32_t idx;
- idx = JS_AtomToUInt32(prop);
+ idx = __JS_AtomToUInt32(prop);
if (idx < p->u.array.count) {
if (desc) {
desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE |
@@ -7883,7 +7954,7 @@ JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
if (tag == JS_TAG_INT &&
(uint32_t)JS_VALUE_GET_INT(val) <= JS_ATOM_MAX_INT) {
/* fast path for integer values */
- atom = JS_AtomFromUInt32(JS_VALUE_GET_INT(val));
+ atom = __JS_AtomFromUInt32(JS_VALUE_GET_INT(val));
} else if (tag == JS_TAG_SYMBOL) {
JSAtomStruct *p = JS_VALUE_GET_PTR(val);
atom = JS_DupAtom(ctx, js_get_atom_index(ctx->rt, p));
@@ -7910,40 +7981,46 @@ static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT &&
JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
JSObject *p;
- uint32_t idx, len;
+ uint32_t idx;
/* fast path for array access */
p = JS_VALUE_GET_OBJ(this_obj);
idx = JS_VALUE_GET_INT(prop);
- len = p->u.array.count;
- if (unlikely(idx >= len))
- goto slow_path;
switch(p->class_id) {
case JS_CLASS_ARRAY:
case JS_CLASS_ARGUMENTS:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return JS_DupValue(ctx, p->u.array.u.values[idx]);
case JS_CLASS_INT8_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return JS_NewInt32(ctx, p->u.array.u.int8_ptr[idx]);
case JS_CLASS_UINT8C_ARRAY:
case JS_CLASS_UINT8_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return JS_NewInt32(ctx, p->u.array.u.uint8_ptr[idx]);
case JS_CLASS_INT16_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return JS_NewInt32(ctx, p->u.array.u.int16_ptr[idx]);
case JS_CLASS_UINT16_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return JS_NewInt32(ctx, p->u.array.u.uint16_ptr[idx]);
case JS_CLASS_INT32_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return JS_NewInt32(ctx, p->u.array.u.int32_ptr[idx]);
case JS_CLASS_UINT32_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return JS_NewUint32(ctx, p->u.array.u.uint32_ptr[idx]);
-#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT64_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]);
case JS_CLASS_BIG_UINT64_ARRAY:
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]);
-#endif
case JS_CLASS_FLOAT32_ARRAY:
- return JS_NewFloat64Impl(ctx, p->u.array.u.float_ptr[idx]);
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
+ return __JS_NewFloat64(ctx, p->u.array.u.float_ptr[idx]);
case JS_CLASS_FLOAT64_ARRAY:
- return JS_NewFloat64Impl(ctx, p->u.array.u.double_ptr[idx]);
+ if (unlikely(idx >= p->u.array.count)) goto slow_path;
+ return __JS_NewFloat64(ctx, p->u.array.u.double_ptr[idx]);
default:
goto slow_path;
}
@@ -7978,7 +8055,7 @@ static int JS_TryGetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx,
if (likely((uint64_t)idx <= JS_ATOM_MAX_INT)) {
/* fast path */
- present = JS_HasProperty(ctx, obj, JS_AtomFromUInt32(idx));
+ present = JS_HasProperty(ctx, obj, __JS_AtomFromUInt32(idx));
if (present > 0) {
val = JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx));
if (unlikely(JS_IsException(val)))
@@ -8075,7 +8152,7 @@ static JSProperty *add_property(JSContext *ctx,
/* can be called on Array or Arguments objects. return < 0 if
memory alloc error. */
-static no_inline warn_unused int convert_fast_array_to_array(JSContext *ctx,
+static no_inline __exception int convert_fast_array_to_array(JSContext *ctx,
JSObject *p)
{
JSProperty *pr;
@@ -8097,8 +8174,8 @@ static no_inline warn_unused int convert_fast_array_to_array(JSContext *ctx,
tab = p->u.array.u.values;
for(i = 0; i < len; i++) {
/* add_property cannot fail here but
- JS_AtomFromUInt32(i) fails for i > INT32_MAX */
- pr = add_property(ctx, p, JS_AtomFromUInt32(i), JS_PROP_C_W_E);
+ __JS_AtomFromUInt32(i) fails for i > INT32_MAX */
+ pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E);
pr->u.value = *tab++;
}
js_free(ctx, p->u.array.u.values);
@@ -8203,7 +8280,7 @@ static int call_setter(JSContext *ctx, JSObject *setter,
func = JS_MKPTR(JS_TAG_OBJECT, setter);
/* Note: the field could be removed in the setter */
func = JS_DupValue(ctx, func);
- ret = JS_CallFree(ctx, func, this_obj, 1, &val);
+ ret = JS_CallFree(ctx, func, this_obj, 1, (JSValueConst *)&val);
JS_FreeValue(ctx, val);
if (JS_IsException(ret))
return -1;
@@ -8360,126 +8437,45 @@ static int add_fast_array_element(JSContext *ctx, JSObject *p,
return TRUE;
}
-static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc)
+/* Allocate a new fast array. Its 'length' property is set to zero. It
+ maximum size is 2^31-1 elements. For convenience, 'len' is a 64 bit
+ integer. WARNING: the content of the array is not initialized. */
+static JSValue js_allocate_fast_array(JSContext *ctx, int64_t len)
{
- JS_FreeValue(ctx, desc->getter);
- JS_FreeValue(ctx, desc->setter);
- JS_FreeValue(ctx, desc->value);
-}
-
-/* generic (and slower) version of JS_SetProperty() for
- * Reflect.set(). 'obj' must be an object. */
-static int JS_SetPropertyGeneric(JSContext *ctx,
- JSValueConst obj, JSAtom prop,
- JSValue val, JSValueConst this_obj,
- int flags)
-{
- int ret;
- JSPropertyDescriptor desc;
- JSValue obj1;
+ JSValue arr;
JSObject *p;
- obj1 = JS_DupValue(ctx, obj);
- for(;;) {
- p = JS_VALUE_GET_OBJ(obj1);
- if (p->is_exotic) {
- const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
- if (em && em->set_property) {
- ret = em->set_property(ctx, obj1, prop,
- val, this_obj, flags);
- JS_FreeValue(ctx, obj1);
- JS_FreeValue(ctx, val);
- return ret;
- }
- }
-
- ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
- if (ret < 0) {
- JS_FreeValue(ctx, obj1);
- JS_FreeValue(ctx, val);
- return ret;
- }
- if (ret) {
- if (desc.flags & JS_PROP_GETSET) {
- JSObject *setter;
- if (JS_IsUndefined(desc.setter))
- setter = NULL;
- else
- setter = JS_VALUE_GET_OBJ(desc.setter);
- ret = call_setter(ctx, setter, this_obj, val, flags);
- JS_FreeValue(ctx, desc.getter);
- JS_FreeValue(ctx, desc.setter);
- JS_FreeValue(ctx, obj1);
- return ret;
- } else {
- JS_FreeValue(ctx, desc.value);
- if (!(desc.flags & JS_PROP_WRITABLE)) {
- JS_FreeValue(ctx, obj1);
- goto read_only_error;
- }
- }
- break;
- }
- /* Note: at this point 'obj1' cannot be a proxy. XXX: may have
- to check recursion */
- obj1 = JS_GetPrototypeFree(ctx, obj1);
- if (JS_IsNull(obj1))
- break;
- }
- JS_FreeValue(ctx, obj1);
-
- if (!JS_IsObject(this_obj)) {
- JS_FreeValue(ctx, val);
- return JS_ThrowTypeErrorOrFalse(ctx, flags, "receiver is not an object");
- }
-
- p = JS_VALUE_GET_OBJ(this_obj);
-
- /* modify the property in this_obj if it already exists */
- ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
- if (ret < 0) {
- JS_FreeValue(ctx, val);
- return ret;
- }
- if (ret) {
- if (desc.flags & JS_PROP_GETSET) {
- JS_FreeValue(ctx, desc.getter);
- JS_FreeValue(ctx, desc.setter);
- JS_FreeValue(ctx, val);
- return JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden");
- } else {
- JS_FreeValue(ctx, desc.value);
- if (!(desc.flags & JS_PROP_WRITABLE) ||
- p->class_id == JS_CLASS_MODULE_NS) {
- read_only_error:
- JS_FreeValue(ctx, val);
- return JS_ThrowTypeErrorReadOnly(ctx, flags, prop);
- }
+ if (len > INT32_MAX)
+ return JS_ThrowRangeError(ctx, "invalid array length");
+ arr = JS_NewArray(ctx);
+ if (JS_IsException(arr))
+ return arr;
+ if (len > 0) {
+ p = JS_VALUE_GET_OBJ(arr);
+ if (expand_fast_array(ctx, p, len) < 0) {
+ JS_FreeValue(ctx, arr);
+ return JS_EXCEPTION;
}
- ret = JS_DefineProperty(ctx, this_obj, prop, val,
- JS_UNDEFINED, JS_UNDEFINED,
- JS_PROP_HAS_VALUE);
- JS_FreeValue(ctx, val);
- return ret;
+ p->u.array.count = len;
}
+ return arr;
+}
- ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED,
- flags |
- JS_PROP_HAS_VALUE |
- JS_PROP_HAS_ENUMERABLE |
- JS_PROP_HAS_WRITABLE |
- JS_PROP_HAS_CONFIGURABLE |
- JS_PROP_C_W_E);
- JS_FreeValue(ctx, val);
- return ret;
+static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc)
+{
+ JS_FreeValue(ctx, desc->getter);
+ JS_FreeValue(ctx, desc->setter);
+ JS_FreeValue(ctx, desc->value);
}
/* return -1 in case of exception or TRUE or FALSE. Warning: 'val' is
freed by the function. 'flags' is a bitmask of JS_PROP_NO_ADD,
JS_PROP_THROW or JS_PROP_THROW_STRICT. If JS_PROP_NO_ADD is set,
- the new property is not added and an error is raised. */
-int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj,
- JSAtom prop, JSValue val, int flags)
+ the new property is not added and an error is raised. 'this_obj' is
+ the receiver. If obj != this_obj, then obj must be an object
+ (Reflect.set case). */
+int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj,
+ JSAtom prop, JSValue val, JSValueConst this_obj, int flags)
{
JSObject *p, *p1;
JSShapeProperty *prs;
@@ -8492,25 +8488,37 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj,
#endif
tag = JS_VALUE_GET_TAG(this_obj);
if (unlikely(tag != JS_TAG_OBJECT)) {
- switch(tag) {
- case JS_TAG_NULL:
- JS_FreeValue(ctx, val);
- JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop);
- return -1;
- case JS_TAG_UNDEFINED:
- JS_FreeValue(ctx, val);
- JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop);
- return -1;
- default:
- /* even on a primitive type we can have setters on the prototype */
+ if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
p = NULL;
- p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, this_obj));
+ p1 = JS_VALUE_GET_OBJ(obj);
goto prototype_lookup;
+ } else {
+ switch(tag) {
+ case JS_TAG_NULL:
+ JS_FreeValue(ctx, val);
+ JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop);
+ return -1;
+ case JS_TAG_UNDEFINED:
+ JS_FreeValue(ctx, val);
+ JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop);
+ return -1;
+ default:
+ /* even on a primitive type we can have setters on the prototype */
+ p = NULL;
+ p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj));
+ goto prototype_lookup;
+ }
}
+ } else {
+ p = JS_VALUE_GET_OBJ(this_obj);
+ p1 = JS_VALUE_GET_OBJ(obj);
+ if (unlikely(p != p1))
+ goto retry2;
}
- p = JS_VALUE_GET_OBJ(this_obj);
-retry:
- prs = find_own_property(&pr, p, prop);
+
+ /* fast path if obj == this_obj */
+ retry:
+ prs = find_own_property(&pr, p1, prop);
if (prs) {
if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE |
JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) {
@@ -8543,12 +8551,11 @@ retry:
}
}
- p1 = p;
for(;;) {
if (p1->is_exotic) {
if (p1->fast_array) {
- if (JS_AtomIsTaggedInt(prop)) {
- uint32_t idx = JS_AtomToUInt32(prop);
+ if (__JS_AtomIsTaggedInt(prop)) {
+ uint32_t idx = __JS_AtomToUInt32(prop);
if (idx < p1->u.array.count) {
if (unlikely(p == p1))
return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val, flags);
@@ -8567,11 +8574,19 @@ retry:
return -1;
}
typed_array_oob:
- val = JS_ToNumberFree(ctx, val);
- JS_FreeValue(ctx, val);
- if (JS_IsException(val))
- return -1;
- return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
+ /* must convert the argument even if out of bound access */
+ if (p1->class_id == JS_CLASS_BIG_INT64_ARRAY ||
+ p1->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
+ int64_t v;
+ if (JS_ToBigInt64Free(ctx, &v, val))
+ return -1;
+ } else {
+ val = JS_ToNumberFree(ctx, val);
+ JS_FreeValue(ctx, val);
+ if (JS_IsException(val))
+ return -1;
+ }
+ return TRUE;
}
}
} else {
@@ -8643,9 +8658,7 @@ retry:
return -1;
goto retry2;
} else if (!(prs->flags & JS_PROP_WRITABLE)) {
- read_only_prop:
- JS_FreeValue(ctx, val);
- return JS_ThrowTypeErrorReadOnly(ctx, flags, prop);
+ goto read_only_prop;
}
}
}
@@ -8666,17 +8679,57 @@ retry:
return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
}
- if (p->is_exotic) {
- if (p->class_id == JS_CLASS_ARRAY && p->fast_array &&
- JS_AtomIsTaggedInt(prop)) {
- uint32_t idx = JS_AtomToUInt32(prop);
- if (idx == p->u.array.count) {
- /* fast case */
- return add_fast_array_element(ctx, p, val, flags);
+ if (likely(p == JS_VALUE_GET_OBJ(obj))) {
+ if (p->is_exotic) {
+ if (p->class_id == JS_CLASS_ARRAY && p->fast_array &&
+ __JS_AtomIsTaggedInt(prop)) {
+ uint32_t idx = __JS_AtomToUInt32(prop);
+ if (idx == p->u.array.count) {
+ /* fast case */
+ return add_fast_array_element(ctx, p, val, flags);
+ } else {
+ goto generic_create_prop;
+ }
} else {
goto generic_create_prop;
}
} else {
+ pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
+ if (unlikely(!pr)) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ pr->u.value = val;
+ return TRUE;
+ }
+ } else {
+ /* generic case: modify the property in this_obj if it already exists */
+ ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
+ if (ret < 0) {
+ JS_FreeValue(ctx, val);
+ return ret;
+ }
+ if (ret) {
+ if (desc.flags & JS_PROP_GETSET) {
+ JS_FreeValue(ctx, desc.getter);
+ JS_FreeValue(ctx, desc.setter);
+ JS_FreeValue(ctx, val);
+ return JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden");
+ } else {
+ JS_FreeValue(ctx, desc.value);
+ if (!(desc.flags & JS_PROP_WRITABLE) ||
+ p->class_id == JS_CLASS_MODULE_NS) {
+ read_only_prop:
+ JS_FreeValue(ctx, val);
+ return JS_ThrowTypeErrorReadOnly(ctx, flags, prop);
+ }
+ }
+ ret = JS_DefineProperty(ctx, this_obj, prop, val,
+ JS_UNDEFINED, JS_UNDEFINED,
+ JS_PROP_HAS_VALUE);
+ JS_FreeValue(ctx, val);
+ return ret;
+ } else {
generic_create_prop:
ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED,
flags |
@@ -8689,14 +8742,6 @@ retry:
return ret;
}
}
-
- pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
- if (unlikely(!pr)) {
- JS_FreeValue(ctx, val);
- return -1;
- }
- pr->u.value = val;
- return TRUE;
}
/* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */
@@ -8720,7 +8765,7 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
JSShape *sh1;
/* fast path to add an element to the array */
- if (idx != p->u.array.count ||
+ if (idx != (uint32_t)p->u.array.count ||
!p->fast_array || !p->extensible)
goto slow_path;
/* check if prototype chain has a numeric property */
@@ -8781,7 +8826,6 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
goto ta_out_of_bound;
p->u.array.u.uint32_ptr[idx] = v;
break;
-#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT64_ARRAY:
case JS_CLASS_BIG_UINT64_ARRAY:
/* XXX: need specific conversion function */
@@ -8794,7 +8838,6 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
p->u.array.u.uint64_ptr[idx] = v;
}
break;
-#endif
case JS_CLASS_FLOAT32_ARRAY:
if (JS_ToFloat64Free(ctx, &d, val))
return -1;
@@ -8807,7 +8850,7 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
return -1;
if (unlikely(idx >= (uint32_t)p->u.array.count)) {
ta_out_of_bound:
- return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
+ return TRUE;
}
p->u.array.u.double_ptr[idx] = d;
break;
@@ -8825,7 +8868,7 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
JS_FreeValue(ctx, val);
return -1;
}
- ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, flags);
+ ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, flags);
JS_FreeAtom(ctx, atom);
return ret;
}
@@ -8865,7 +8908,7 @@ int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj,
JSAtom atom;
int ret;
atom = JS_NewAtom(ctx, prop);
- ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, JS_PROP_THROW);
+ ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, JS_PROP_THROW);
JS_FreeAtom(ctx, atom);
return ret;
}
@@ -8895,8 +8938,8 @@ static int JS_CreateProperty(JSContext *ctx, JSObject *p,
uint32_t idx, len;
if (p->fast_array) {
- if (JS_AtomIsTaggedInt(prop)) {
- idx = JS_AtomToUInt32(prop);
+ if (__JS_AtomIsTaggedInt(prop)) {
+ idx = __JS_AtomToUInt32(prop);
if (idx == p->u.array.count) {
if (!p->extensible)
goto not_extensible;
@@ -9205,15 +9248,19 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
spaces. */
if (!js_same_value(ctx, val, *pr->u.var_ref->pvalue))
goto not_configurable;
+ } else {
+ /* update the reference */
+ set_value(ctx, pr->u.var_ref->pvalue,
+ JS_DupValue(ctx, val));
}
- /* update the reference */
- set_value(ctx, pr->u.var_ref->pvalue,
- JS_DupValue(ctx, val));
}
/* if writable is set to false, no longer a
reference (for mapped arguments) */
if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) {
JSValue val1;
+ if (p->class_id == JS_CLASS_MODULE_NS) {
+ return JS_ThrowTypeErrorOrFalse(ctx, flags, "module namespace properties have writable = false");
+ }
if (js_shape_prepare_update(ctx, p, &prs))
return -1;
val1 = JS_DupValue(ctx, *pr->u.var_ref->pvalue);
@@ -9272,8 +9319,8 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
uint32_t idx;
uint32_t prop_flags;
if (p->class_id == JS_CLASS_ARRAY) {
- if (JS_AtomIsTaggedInt(prop)) {
- idx = JS_AtomToUInt32(prop);
+ if (__JS_AtomIsTaggedInt(prop)) {
+ idx = __JS_AtomToUInt32(prop);
if (idx < p->u.array.count) {
prop_flags = get_prop_flags(flags, JS_PROP_C_W_E);
if (prop_flags != JS_PROP_C_W_E)
@@ -9296,7 +9343,7 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
JSValue num;
int ret;
- if (!JS_AtomIsTaggedInt(prop)) {
+ if (!__JS_AtomIsTaggedInt(prop)) {
/* slow path with to handle all numeric indexes */
num = JS_AtomIsNumericIndex1(ctx, prop);
if (JS_IsUndefined(num))
@@ -9317,12 +9364,12 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
if (ret) {
return JS_ThrowTypeErrorOrFalse(ctx, flags, "negative index in typed array");
}
- if (!JS_AtomIsTaggedInt(prop))
+ if (!__JS_AtomIsTaggedInt(prop))
goto typed_array_oob;
}
- idx = JS_AtomToUInt32(prop);
+ idx = __JS_AtomToUInt32(prop);
/* if the typed array is detached, p->u.array.count = 0 */
- if (idx >= typed_array_get_length(ctx, p)) {
+ if (idx >= p->u.array.count) {
typed_array_oob:
return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound index in typed array");
}
@@ -9726,11 +9773,11 @@ static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val,
struct LookupResult result = ctx->scopeLookup(ctx, prop);
if (result.useResult) {
JS_FreeValue(ctx, result.value);
- return JS_SetPropertyInternal(ctx, result.scope, prop, val, flags);
+ return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, result.scope, flags);
}
}
- return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags);
+ return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, ctx->global_obj, flags);
}
/* return -1, FALSE or TRUE. return FALSE if not configurable or
@@ -9765,7 +9812,7 @@ int JS_DeletePropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, int fl
if ((uint64_t)idx <= JS_ATOM_MAX_INT) {
/* fast path for fast arrays */
- return JS_DeleteProperty(ctx, obj, JS_AtomFromUInt32(idx), flags);
+ return JS_DeleteProperty(ctx, obj, __JS_AtomFromUInt32(idx), flags);
}
prop = JS_NewAtomInt64(ctx, idx);
if (prop == JS_ATOM_NULL)
@@ -9822,6 +9869,14 @@ BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, BOOL val)
return TRUE;
}
+JS_BOOL JS_IsArrayBuffer(JSValueConst v)
+{
+ if (!JS_IsObject(v))
+ return FALSE;
+ JSObject *p = JS_VALUE_GET_OBJ(v);
+ return p->class_id == JS_CLASS_ARRAY_BUFFER || p->class_id == JS_CLASS_SHARED_ARRAY_BUFFER;
+}
+
BOOL JS_IsError(JSContext *ctx, JSValueConst val)
{
JSObject *p;
@@ -9886,12 +9941,6 @@ void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id)
return p;
}
-#define HINT_STRING 0
-#define HINT_NUMBER 1
-#define HINT_NONE 2
-/* don't try Symbol.toPrimitive */
-#define HINT_FORCE_ORDINARY (1 << 4)
-
static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint)
{
int i;
@@ -9925,7 +9974,7 @@ static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint)
break;
}
arg = JS_AtomToString(ctx, atom);
- ret = JS_CallFree(ctx, method, val, 1, &arg);
+ ret = JS_CallFree(ctx, method, val, 1, (JSValueConst *)&arg);
JS_FreeValue(ctx, arg);
if (JS_IsException(ret))
goto exception;
@@ -10007,9 +10056,10 @@ static int JS_ToBoolFree(JSContext *ctx, JSValue val)
JS_FreeValue(ctx, val);
return ret;
}
-#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
+#endif
{
JSBigFloat *p = JS_VALUE_GET_PTR(val);
BOOL ret;
@@ -10017,6 +10067,7 @@ static int JS_ToBoolFree(JSContext *ctx, JSValue val)
JS_FreeValue(ctx, val);
return ret;
}
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_DECIMAL:
{
JSBigDecimal *p = JS_VALUE_GET_PTR(val);
@@ -10086,12 +10137,13 @@ static inline int to_digit(int c)
}
/* XXX: remove */
-static double js_strtod(const char *p, int radix, BOOL is_float)
+static double js_strtod(const char *str, int radix, BOOL is_float)
{
double d;
int c;
if (!is_float || radix != 10) {
+ const char *p = str;
uint64_t n_max, n;
int int_exp, is_neg;
@@ -10118,6 +10170,8 @@ static double js_strtod(const char *p, int radix, BOOL is_float)
if (n <= n_max) {
n = n * radix + c;
} else {
+ if (radix == 10)
+ goto strtod_case;
int_exp++;
}
p++;
@@ -10129,7 +10183,8 @@ static double js_strtod(const char *p, int radix, BOOL is_float)
if (is_neg)
d = -d;
} else {
- d = safe_strtod(p, NULL);
+ strtod_case:
+ d = safe_strtod(str, NULL);
}
return d;
}
@@ -10147,15 +10202,16 @@ static double js_strtod(const char *p, int radix, BOOL is_float)
#define ATOD_TYPE_MASK (3 << 7)
#define ATOD_TYPE_FLOAT64 (0 << 7)
#define ATOD_TYPE_BIG_INT (1 << 7)
+#ifdef CONFIG_BIGNUM
#define ATOD_TYPE_BIG_FLOAT (2 << 7)
#define ATOD_TYPE_BIG_DECIMAL (3 << 7)
/* assume bigint mode: floats are parsed as integers if no decimal
point nor exponent */
#define ATOD_MODE_BIGINT (1 << 9)
+#endif
/* accept -0x1 */
#define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10)
-#ifdef CONFIG_BIGNUM
static JSValue js_string_to_bigint(JSContext *ctx, const char *buf,
int radix, int flags, slimb_t *pexponent)
{
@@ -10171,10 +10227,15 @@ static JSValue js_string_to_bigint(JSContext *ctx, const char *buf,
JS_FreeValue(ctx, val);
return JS_ThrowOutOfMemory(ctx);
}
+#ifdef CONFIG_BIGNUM
val = JS_CompactBigInt1(ctx, val, (flags & ATOD_MODE_BIGINT) != 0);
+#else
+ val = JS_CompactBigInt1(ctx, val, FALSE);
+#endif
return val;
}
+#ifdef CONFIG_BIGNUM
static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf,
int radix, int flags, slimb_t *pexponent)
{
@@ -10220,7 +10281,6 @@ static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf,
}
return val;
}
-
#endif
/* return an exception in case of memory error. Return JS_NAN if
@@ -10295,8 +10355,11 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
} else {
no_radix_prefix:
if (!(flags & ATOD_INT_ONLY) &&
- (atod_type == ATOD_TYPE_FLOAT64 ||
- atod_type == ATOD_TYPE_BIG_FLOAT) &&
+ (atod_type == ATOD_TYPE_FLOAT64
+#ifdef CONFIG_BIGNUM
+ || atod_type == ATOD_TYPE_BIG_FLOAT
+#endif
+ ) &&
strstart(p, "Infinity", &p)) {
#ifdef CONFIG_BIGNUM
if (atod_type == ATOD_TYPE_BIG_FLOAT) {
@@ -10342,8 +10405,11 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
((*p == 'p' || *p == 'P') && (radix == 2 || radix == 8 || radix == 16)))) {
const char *p1 = p + 1;
is_float = TRUE;
- if (*p1 == '+' || *p1 == '-')
+ if (*p1 == '+') {
p1++;
+ } else if (*p1 == '-') {
+ p1++;
+ }
if (is_digit((uint8_t)*p1)) {
p = p1 + 1;
while (is_digit((uint8_t)*p) || (*p == sep && is_digit((uint8_t)p[1])))
@@ -10373,36 +10439,40 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
}
buf[j] = '\0';
-#ifdef CONFIG_BIGNUM
if (flags & ATOD_ACCEPT_SUFFIX) {
if (*p == 'n') {
p++;
atod_type = ATOD_TYPE_BIG_INT;
- } else if (*p == 'l') {
+ } else
+#ifdef CONFIG_BIGNUM
+ if (*p == 'l') {
p++;
atod_type = ATOD_TYPE_BIG_FLOAT;
} else if (*p == 'm') {
p++;
atod_type = ATOD_TYPE_BIG_DECIMAL;
- } else {
- if (flags & ATOD_MODE_BIGINT) {
- if (!is_float)
- atod_type = ATOD_TYPE_BIG_INT;
- if (has_legacy_octal)
- goto fail;
- } else {
- if (is_float && radix != 10)
- goto fail;
- }
+ } else if (flags & ATOD_MODE_BIGINT) {
+ if (!is_float)
+ atod_type = ATOD_TYPE_BIG_INT;
+ if (has_legacy_octal)
+ goto fail;
+ } else
+#endif
+ {
+ if (is_float && radix != 10)
+ goto fail;
}
} else {
if (atod_type == ATOD_TYPE_FLOAT64) {
+#ifdef CONFIG_BIGNUM
if (flags & ATOD_MODE_BIGINT) {
if (!is_float)
atod_type = ATOD_TYPE_BIG_INT;
if (has_legacy_octal)
goto fail;
- } else {
+ } else
+#endif
+ {
if (is_float && radix != 10)
goto fail;
}
@@ -10423,6 +10493,7 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
goto fail;
val = ctx->rt->bigint_ops.from_string(ctx, buf, radix, flags, NULL);
break;
+#ifdef CONFIG_BIGNUM
case ATOD_TYPE_BIG_FLOAT:
if (has_legacy_octal)
goto fail;
@@ -10434,19 +10505,10 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
goto fail;
val = ctx->rt->bigdecimal_ops.from_string(ctx, buf, radix, flags, NULL);
break;
+#endif
default:
abort();
}
-#else
- {
- double d;
- (void)has_legacy_octal;
- if (is_float && radix != 10)
- goto fail;
- d = js_strtod(buf, radix, is_float);
- val = JS_NewFloat64(ctx, d);
- }
-#endif
done:
if (buf_allocated)
@@ -10484,18 +10546,18 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val,
redo:
tag = JS_VALUE_GET_NORM_TAG(val);
switch(tag) {
-#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_DECIMAL:
+ case JS_TAG_BIG_INT:
if (flag != TON_FLAG_NUMERIC) {
JS_FreeValue(ctx, val);
- return JS_ThrowTypeError(ctx, "cannot convert bigdecimal to number");
+ return JS_ThrowTypeError(ctx, "cannot convert bigint to number");
}
ret = val;
break;
- case JS_TAG_BIG_INT:
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_DECIMAL:
if (flag != TON_FLAG_NUMERIC) {
JS_FreeValue(ctx, val);
- return JS_ThrowTypeError(ctx, "cannot convert bigint to number");
+ return JS_ThrowTypeError(ctx, "cannot convert bigdecimal to number");
}
ret = val;
break;
@@ -10578,7 +10640,7 @@ static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val)
return JS_ToNumericFree(ctx, JS_DupValue(ctx, val));
}
-static warn_unused int JS_ToFloat64FreeImpl(JSContext *ctx, double *pres,
+static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres,
JSValue val)
{
double d;
@@ -10597,9 +10659,10 @@ static warn_unused int JS_ToFloat64FreeImpl(JSContext *ctx, double *pres,
case JS_TAG_FLOAT64:
d = JS_VALUE_GET_FLOAT64(val);
break;
-#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
+#endif
{
JSBigFloat *p = JS_VALUE_GET_PTR(val);
/* XXX: there can be a double rounding issue with some
@@ -10609,7 +10672,6 @@ static warn_unused int JS_ToFloat64FreeImpl(JSContext *ctx, double *pres,
JS_FreeValue(ctx, val);
}
break;
-#endif
default:
abort();
}
@@ -10629,7 +10691,7 @@ static inline int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val)
*pres = JS_VALUE_GET_FLOAT64(val);
return 0;
} else {
- return JS_ToFloat64FreeImpl(ctx, pres, val);
+ return __JS_ToFloat64Free(ctx, pres, val);
}
}
@@ -10644,7 +10706,7 @@ static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val)
}
/* same as JS_ToNumber() but return 0 in case of NaN/Undefined */
-static maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
+static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
{
uint32_t tag;
JSValue ret;
@@ -10677,6 +10739,10 @@ static maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
BOOL is_nan;
a = JS_ToBigFloat(ctx, &a_s, val);
+ if (!a) {
+ JS_FreeValue(ctx, val);
+ return JS_EXCEPTION;
+ }
if (!bf_is_finite(a)) {
is_nan = bf_is_nan(a);
if (is_nan)
@@ -10807,7 +10873,7 @@ static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val)
} else {
if (d < INT64_MIN)
*pres = INT64_MIN;
- else if (d > INT64_MAX)
+ else if (d >= 0x1p63) /* must use INT64_MAX + 1 because INT64_MAX cannot be exactly represented as a double */
*pres = INT64_MAX;
else
*pres = (int64_t)d;
@@ -11059,7 +11125,7 @@ static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val)
return 0;
}
-static warn_unused int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
+static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
JSValue val, BOOL is_array_ctor)
{
uint32_t tag, len;
@@ -11077,9 +11143,10 @@ static warn_unused int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
len = v;
}
break;
-#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
+#endif
{
JSBigFloat *p = JS_VALUE_GET_PTR(val);
bf_t a;
@@ -11094,11 +11161,12 @@ static warn_unused int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
goto fail;
}
break;
-#endif
default:
if (JS_TAG_IS_FLOAT64(tag)) {
double d;
d = JS_VALUE_GET_FLOAT64(val);
+ if (!(d >= 0 && d <= UINT32_MAX))
+ goto fail;
len = (uint32_t)d;
if (len != d)
goto fail;
@@ -11161,7 +11229,7 @@ int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val)
/* convert a value to a length between 0 and MAX_SAFE_INTEGER.
return -1 for exception */
-static warn_unused int JS_ToLengthFree(JSContext *ctx, int64_t *plen,
+static __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen,
JSValue val)
{
int res = JS_ToInt64Clamp(ctx, plen, val, 0, MAX_SAFE_INTEGER, 0);
@@ -11198,13 +11266,13 @@ static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val)
u.d = JS_VALUE_GET_FLOAT64(val);
return (u.u64 >> 63);
}
-#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
{
JSBigFloat *p = JS_VALUE_GET_PTR(val);
/* Note: integer zeros are not necessarily positive */
return p->num.sign && !bf_is_zero(&p->num);
}
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
{
JSBigFloat *p = JS_VALUE_GET_PTR(val);
@@ -11223,8 +11291,6 @@ static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val)
}
}
-#ifdef CONFIG_BIGNUM
-
static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix)
{
JSValue ret;
@@ -11254,6 +11320,8 @@ static JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val)
return js_bigint_to_string1(ctx, val, 10);
}
+#ifdef CONFIG_BIGNUM
+
static JSValue js_ftoa(JSContext *ctx, JSValueConst val1, int radix,
limb_t prec, bf_flags_t flags)
{
@@ -11266,6 +11334,10 @@ static JSValue js_ftoa(JSContext *ctx, JSValueConst val1, int radix,
if (JS_IsException(val))
return val;
a = JS_ToBigFloat(ctx, &a_s, val);
+ if (!a) {
+ JS_FreeValue(ctx, val);
+ return JS_EXCEPTION;
+ }
saved_sign = a->sign;
if (a->expn == BF_EXP_ZERO)
a->sign = 0;
@@ -11322,6 +11394,8 @@ static JSValue js_bigdecimal_to_string1(JSContext *ctx, JSValueConst val,
int saved_sign;
a = JS_ToBigDecimal(ctx, val);
+ if (!a)
+ return JS_EXCEPTION;
saved_sign = a->sign;
if (a->expn == BF_EXP_ZERO)
a->sign = 0;
@@ -11343,6 +11417,8 @@ static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val)
#endif /* CONFIG_BIGNUM */
/* 2 <= base <= 36 */
+static char const digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
+
static char *i64toa(char *buf_end, int64_t n, unsigned int base)
{
char *q = buf_end;
@@ -11354,15 +11430,20 @@ static char *i64toa(char *buf_end, int64_t n, unsigned int base)
n = -n;
}
*--q = '\0';
- do {
- digit = (uint64_t)n % base;
- n = (uint64_t)n / base;
- if (digit < 10)
- digit += '0';
- else
- digit += 'a' - 10;
- *--q = digit;
- } while (n != 0);
+ if (base == 10) {
+ /* division by known base uses multiplication */
+ do {
+ digit = (uint64_t)n % 10;
+ n = (uint64_t)n / 10;
+ *--q = '0' + digit;
+ } while (n != 0);
+ } else {
+ do {
+ digit = (uint64_t)n % base;
+ n = (uint64_t)n / base;
+ *--q = digits[digit];
+ } while (n != 0);
+ }
if (is_neg)
*--q = '-';
return q;
@@ -11452,20 +11533,20 @@ static int js_ecvt(double d, int n_digits, int *decpt, int *sign, char *buf,
return n_digits;
}
-static int js_fcvt1(char *buf, int buf_size, double d, int n_digits,
+static int js_fcvt1(char (*buf)[JS_DTOA_BUF_SIZE], double d, int n_digits,
int rounding_mode)
{
int n;
if (rounding_mode != FE_TONEAREST)
fesetround(rounding_mode);
- n = snprintf(buf, buf_size, "%.*f", n_digits, d);
+ n = snprintf(*buf, sizeof(*buf), "%.*f", n_digits, d);
if (rounding_mode != FE_TONEAREST)
fesetround(FE_TONEAREST);
- assert(n < buf_size);
+ assert(n < sizeof(*buf));
return n;
}
-static void js_fcvt(char *buf, int buf_size, double d, int n_digits)
+static void js_fcvt(char (*buf)[JS_DTOA_BUF_SIZE], double d, int n_digits)
{
int rounding_mode;
rounding_mode = FE_TONEAREST;
@@ -11479,12 +11560,12 @@ static void js_fcvt(char *buf, int buf_size, double d, int n_digits)
zero (RNDNA), but in printf the "ties" case is not specified
(for example it is RNDN for glibc, RNDNA for Windows), so we
must round manually. */
- n1 = js_fcvt1(buf1, sizeof(buf1), d, n_digits + 1, FE_TONEAREST);
+ n1 = js_fcvt1(&buf1, d, n_digits + 1, FE_TONEAREST);
rounding_mode = FE_TONEAREST;
/* XXX: could use 2 digits to reduce the average running time */
if (buf1[n1 - 1] == '5') {
- n1 = js_fcvt1(buf1, sizeof(buf1), d, n_digits + 1, FE_DOWNWARD);
- n2 = js_fcvt1(buf2, sizeof(buf2), d, n_digits + 1, FE_UPWARD);
+ n1 = js_fcvt1(&buf1, d, n_digits + 1, FE_DOWNWARD);
+ n2 = js_fcvt1(&buf2, d, n_digits + 1, FE_UPWARD);
if (n1 == n2 && memcmp(buf1, buf2, n1) == 0) {
/* exact result: round away from zero */
if (buf1[0] == '-')
@@ -11495,7 +11576,7 @@ static void js_fcvt(char *buf, int buf_size, double d, int n_digits)
}
}
#endif /* CONFIG_PRINTF_RNDN */
- js_fcvt1(buf, buf_size, d, n_digits, rounding_mode);
+ js_fcvt1(buf, d, n_digits, rounding_mode);
}
/* radix != 10 is only supported with flags = JS_DTOA_VAR_FORMAT */
@@ -11511,33 +11592,35 @@ static void js_fcvt(char *buf, int buf_size, double d, int n_digits)
/* XXX: slow and maybe not fully correct. Use libbf when it is fast enough.
XXX: radix != 10 is only supported for small integers
*/
-static void js_dtoa1(char *buf, double d, int radix, int n_digits, int flags)
+static void js_dtoa1(char (*buf)[JS_DTOA_BUF_SIZE], double d,
+ int radix, int n_digits, int flags)
{
char *q;
if (!isfinite(d)) {
if (isnan(d)) {
- strcpy(buf, "NaN");
+ pstrcpy(*buf, sizeof(*buf), "NaN");
+ } else if (d < 0) {
+ pstrcpy(*buf, sizeof(*buf), "-Infinity");
} else {
- q = buf;
- if (d < 0)
- *q++ = '-';
- strcpy(q, "Infinity");
+ pstrcpy(*buf, sizeof(*buf), "Infinity");
}
} else if (flags == JS_DTOA_VAR_FORMAT) {
int64_t i64;
char buf1[70], *ptr;
+ if (d > (double)MAX_SAFE_INTEGER || d < (double)-MAX_SAFE_INTEGER)
+ goto generic_conv;
i64 = (int64_t)d;
- if (d != i64 || i64 > MAX_SAFE_INTEGER || i64 < -MAX_SAFE_INTEGER)
+ if (d != i64)
goto generic_conv;
/* fast path for integers */
ptr = i64toa(buf1 + sizeof(buf1), i64, radix);
- strcpy(buf, ptr);
+ pstrcpy(*buf, sizeof(*buf), ptr);
} else {
if (d == 0.0)
d = 0.0; /* convert -0 to 0 */
if (flags == JS_DTOA_FRAC_FORMAT) {
- js_fcvt(buf, JS_DTOA_BUF_SIZE, d, n_digits);
+ js_fcvt(buf, d, n_digits);
} else {
char buf1[JS_DTOA_BUF_SIZE];
int sign, decpt, k, n, i, p, n_max;
@@ -11552,7 +11635,7 @@ static void js_dtoa1(char *buf, double d, int radix, int n_digits, int flags)
/* the number has k digits (k >= 1) */
k = js_ecvt(d, n_digits, &decpt, &sign, buf1, is_fixed);
n = decpt; /* d=10^(n-k)*(buf1) i.e. d= < x.yyyy 10^(n-1) */
- q = buf;
+ q = *buf;
if (sign)
*q++ = '-';
if (flags & JS_DTOA_FORCE_EXP)
@@ -11594,7 +11677,7 @@ static void js_dtoa1(char *buf, double d, int radix, int n_digits, int flags)
p = n - 1;
if (p >= 0)
*q++ = '+';
- sprintf(q, "%d", p);
+ snprintf(q, *buf + sizeof(*buf) - q, "%d", p);
}
}
}
@@ -11604,10 +11687,84 @@ static JSValue js_dtoa(JSContext *ctx,
double d, int radix, int n_digits, int flags)
{
char buf[JS_DTOA_BUF_SIZE];
- js_dtoa1(buf, d, radix, n_digits, flags);
+ js_dtoa1(&buf, d, radix, n_digits, flags);
return JS_NewString(ctx, buf);
}
+static JSValue js_dtoa_radix(JSContext *ctx, double d, int radix)
+{
+ char buf[2200], *ptr, *ptr2;
+ /* d is finite */
+ int sign = d < 0;
+ int digit;
+ double frac, d0;
+ int64_t n0 = 0;
+ d = fabs(d);
+ d0 = trunc(d);
+ frac = d - d0;
+ ptr = buf + 1100;
+ *ptr = '\0';
+ if (d0 <= MAX_SAFE_INTEGER) {
+ int64_t n = n0 = (int64_t)d0;
+ while (n >= radix) {
+ digit = n % radix;
+ n = n / radix;
+ *--ptr = digits[digit];
+ }
+ *--ptr = digits[(int)n];
+ } else {
+ /* no decimals */
+ while (d0 >= radix) {
+ digit = fmod(d0, radix);
+ d0 = trunc(d0 / radix);
+ if (d0 >= MAX_SAFE_INTEGER)
+ digit = 0;
+ *--ptr = digits[digit];
+ }
+ *--ptr = digits[(int)d0];
+ goto done;
+ }
+ if (frac != 0) {
+ double log2_radix = log2(radix);
+ double prec = 1023 + 51; // handle subnormals
+ ptr2 = buf + 1100;
+ *ptr2++ = '.';
+ while (frac != 0 && n0 <= MAX_SAFE_INTEGER/2 && prec > 0) {
+ frac *= radix;
+ digit = trunc(frac);
+ frac -= digit;
+ *ptr2++ = digits[digit];
+ n0 = n0 * radix + digit;
+ prec -= log2_radix;
+ }
+ *ptr2 = '\0';
+ if (frac * radix >= radix / 2) {
+ char nine = digits[radix - 1];
+ // round to closest
+ while (ptr2[-1] == nine)
+ *--ptr2 = '\0';
+ if (ptr2[-1] == '.') {
+ *--ptr2 = '\0';
+ while (ptr2[-1] == nine)
+ *--ptr2 = '0';
+ }
+ if (ptr2 - 1 == ptr)
+ *--ptr = '1';
+ else
+ ptr2[-1] += 1;
+ } else {
+ while (ptr2[-1] == '0')
+ *--ptr2 = '\0';
+ if (ptr2[-1] == '.')
+ *--ptr2 = '\0';
+ }
+ }
+done:
+ ptr[-1] = '-';
+ ptr -= sign;
+ return JS_NewString(ctx, ptr);
+}
+
JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToPropertyKey)
{
uint32_t tag;
@@ -11654,9 +11811,9 @@ JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToProperty
case JS_TAG_FLOAT64:
return js_dtoa(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0,
JS_DTOA_VAR_FORMAT);
-#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
return ctx->rt->bigint_ops.to_string(ctx, val);
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
return ctx->rt->bigfloat_ops.to_string(ctx, val);
case JS_TAG_BIG_DECIMAL:
@@ -11748,7 +11905,7 @@ static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1)
goto fail;
break;
default:
- if (c < 32 || (c >= 0xd800 && c < 0xe000)) {
+ if (c < 32 || is_surrogate(c)) {
snprintf(buf, sizeof(buf), "\\u%04x", c);
if (string_buffer_puts8(b, buf))
goto fail;
@@ -11769,14 +11926,14 @@ static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1)
return JS_EXCEPTION;
}
-static maybe_unused void JS_DumpObjectHeader(JSRuntime *rt)
+static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt)
{
printf("%14s %4s %4s %14s %10s %s\n",
"ADDRESS", "REFS", "SHRF", "PROTO", "CLASS", "PROPS");
}
/* for debug only: dump an object without side effect */
-static maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
+static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
{
uint32_t i;
char atom_buf[ATOM_GET_STR_BUF_SIZE];
@@ -11817,10 +11974,8 @@ static maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
case JS_CLASS_UINT16_ARRAY:
case JS_CLASS_INT32_ARRAY:
case JS_CLASS_UINT32_ARRAY:
-#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT64_ARRAY:
case JS_CLASS_BIG_UINT64_ARRAY:
-#endif
case JS_CLASS_FLOAT32_ARRAY:
case JS_CLASS_FLOAT64_ARRAY:
{
@@ -11853,7 +12008,7 @@ static maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
printf("[autoinit %p %d %p]",
(void *)js_autoinit_get_realm(pr),
js_autoinit_get_id(pr),
- pr->u.init.opaque);
+ (void *)pr->u.init.opaque);
} else {
JS_DumpValueShort(rt, pr->u.value);
}
@@ -11882,7 +12037,7 @@ static maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
printf("\n");
}
-static maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p)
+static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p)
{
if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
JS_DumpObject(rt, (JSObject *)p);
@@ -11914,7 +12069,7 @@ static maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p)
}
}
-static maybe_unused void JS_DumpValueShort(JSRuntime *rt,
+static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
JSValueConst val)
{
uint32_t tag = JS_VALUE_GET_NORM_TAG(val);
@@ -11947,7 +12102,6 @@ static maybe_unused void JS_DumpValueShort(JSRuntime *rt,
case JS_TAG_FLOAT64:
printf("%.14g", JS_VALUE_GET_FLOAT64(val));
break;
-#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
{
JSBigFloat *p = JS_VALUE_GET_PTR(val);
@@ -11958,6 +12112,7 @@ static maybe_unused void JS_DumpValueShort(JSRuntime *rt,
bf_realloc(&rt->bf_ctx, str, 0);
}
break;
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
{
JSBigFloat *p = JS_VALUE_GET_PTR(val);
@@ -12019,13 +12174,13 @@ static maybe_unused void JS_DumpValueShort(JSRuntime *rt,
}
}
-static maybe_unused void JS_DumpValue(JSContext *ctx,
+static __maybe_unused void JS_DumpValue(JSContext *ctx,
JSValueConst val)
{
JS_DumpValueShort(ctx->rt, val);
}
-static maybe_unused void JS_PrintValue(JSContext *ctx,
+static __maybe_unused void JS_PrintValue(JSContext *ctx,
const char *str,
JSValueConst val)
{
@@ -12035,15 +12190,14 @@ static maybe_unused void JS_PrintValue(JSContext *ctx,
}
/* return -1 if exception (proxy case) or TRUE/FALSE */
+// TODO: should take flags to make proxy resolution and exceptions optional
int JS_IsArray(JSContext *ctx, JSValueConst val)
{
- JSObject *p;
+ if (js_resolve_proxy(ctx, &val, TRUE))
+ return -1;
if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {
- p = JS_VALUE_GET_OBJ(val);
- if (unlikely(p->class_id == JS_CLASS_PROXY))
- return js_proxy_isArray(ctx, val);
- else
- return p->class_id == JS_CLASS_ARRAY;
+ JSObject *p = JS_VALUE_GET_OBJ(val);
+ return p->class_id == JS_CLASS_ARRAY;
} else {
return FALSE;
}
@@ -12059,8 +12213,6 @@ static double js_pow(double a, double b)
}
}
-#ifdef CONFIG_BIGNUM
-
JSValue JS_NewBigInt64_1(JSContext *ctx, int64_t v)
{
JSValue val;
@@ -12105,70 +12257,6 @@ JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
return val;
}
-/* if the returned bigfloat is allocated it is equal to
- 'buf'. Otherwise it is a pointer to the bigfloat in 'val'. Return
- NULL in case of error. */
-static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val)
-{
- uint32_t tag;
- bf_t *r;
- JSBigFloat *p;
-
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_INT:
- case JS_TAG_BOOL:
- case JS_TAG_NULL:
- r = buf;
- bf_init(ctx->bf_ctx, r);
- if (bf_set_si(r, JS_VALUE_GET_INT(val)))
- goto fail;
- break;
- case JS_TAG_FLOAT64:
- r = buf;
- bf_init(ctx->bf_ctx, r);
- if (bf_set_float64(r, JS_VALUE_GET_FLOAT64(val))) {
- fail:
- bf_delete(r);
- return NULL;
- }
- break;
- case JS_TAG_BIG_INT:
- case JS_TAG_BIG_FLOAT:
- p = JS_VALUE_GET_PTR(val);
- r = &p->num;
- break;
- case JS_TAG_UNDEFINED:
- default:
- r = buf;
- bf_init(ctx->bf_ctx, r);
- bf_set_nan(r);
- break;
- }
- return r;
-}
-
-/* return NULL if invalid type */
-static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val)
-{
- uint32_t tag;
- JSBigDecimal *p;
- bfdec_t *r;
-
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_BIG_DECIMAL:
- p = JS_VALUE_GET_PTR(val);
- r = &p->num;
- break;
- default:
- JS_ThrowTypeError(ctx, "bigdecimal expected");
- r = NULL;
- break;
- }
- return r;
-}
-
/* return NaN if bad bigint literal */
static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val)
{
@@ -12186,8 +12274,10 @@ static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val)
val = JS_NewBigInt64(ctx, 0);
} else {
flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT;
+#ifdef CONFIG_BIGNUM
if (is_math_mode(ctx))
flags |= ATOD_MODE_BIGINT;
+#endif
val = js_atof(ctx, p, &p, 0, flags);
p += skip_spaces(p);
if (!JS_IsException(val)) {
@@ -12248,6 +12338,7 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val)
p = JS_VALUE_GET_PTR(val);
r = &p->num;
break;
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
if (!is_math_mode(ctx))
goto fail;
@@ -12260,6 +12351,7 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val)
bf_rint(r, BF_RNDZ);
JS_FreeValue(ctx, val);
break;
+#endif
case JS_TAG_STRING:
val = JS_StringToBigIntErr(ctx, val);
if (JS_IsException(val))
@@ -12320,7 +12412,7 @@ static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf)
} else {
JSBigFloat *p = (JSBigFloat *)((uint8_t *)a -
offsetof(JSBigFloat, num));
- JS_FreeValue(ctx, JS_MKPTR(JS_TAG_BIG_FLOAT, p));
+ JS_FreeValue(ctx, JS_MKPTR(JS_TAG_BIG_INT, p));
}
}
@@ -12355,28 +12447,6 @@ static JSBigFloat *js_new_bf(JSContext *ctx)
return p;
}
-static JSValue JS_NewBigFloat(JSContext *ctx)
-{
- JSBigFloat *p;
- p = js_malloc(ctx, sizeof(*p));
- if (!p)
- return JS_EXCEPTION;
- p->header.ref_count = 1;
- bf_init(ctx->bf_ctx, &p->num);
- return JS_MKPTR(JS_TAG_BIG_FLOAT, p);
-}
-
-static JSValue JS_NewBigDecimal(JSContext *ctx)
-{
- JSBigDecimal *p;
- p = js_malloc(ctx, sizeof(*p));
- if (!p)
- return JS_EXCEPTION;
- p->header.ref_count = 1;
- bfdec_init(ctx->bf_ctx, &p->num);
- return JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
-}
-
static JSValue JS_NewBigInt(JSContext *ctx)
{
JSBigFloat *p;
@@ -12418,6 +12488,110 @@ static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val)
return JS_CompactBigInt1(ctx, val, is_math_mode(ctx));
}
+static JSValue throw_bf_exception(JSContext *ctx, int status)
+{
+ const char *str;
+ if (status & BF_ST_MEM_ERROR)
+ return JS_ThrowOutOfMemory(ctx);
+ if (status & BF_ST_DIVIDE_ZERO) {
+ str = "division by zero";
+ } else if (status & BF_ST_INVALID_OP) {
+ str = "invalid operation";
+ } else {
+ str = "integer overflow";
+ }
+ return JS_ThrowRangeError(ctx, "%s", str);
+}
+
+/* if the returned bigfloat is allocated it is equal to
+ 'buf'. Otherwise it is a pointer to the bigfloat in 'val'. Return
+ NULL in case of error. */
+static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val)
+{
+ uint32_t tag;
+ bf_t *r;
+ JSBigFloat *p;
+
+ tag = JS_VALUE_GET_NORM_TAG(val);
+ switch(tag) {
+ case JS_TAG_INT:
+ case JS_TAG_BOOL:
+ case JS_TAG_NULL:
+ r = buf;
+ bf_init(ctx->bf_ctx, r);
+ if (bf_set_si(r, JS_VALUE_GET_INT(val)))
+ goto fail;
+ break;
+ case JS_TAG_FLOAT64:
+ r = buf;
+ bf_init(ctx->bf_ctx, r);
+ if (bf_set_float64(r, JS_VALUE_GET_FLOAT64(val))) {
+ fail:
+ bf_delete(r);
+ return NULL;
+ }
+ break;
+ case JS_TAG_BIG_INT:
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_FLOAT:
+#endif
+ p = JS_VALUE_GET_PTR(val);
+ r = &p->num;
+ break;
+ case JS_TAG_UNDEFINED:
+ default:
+ r = buf;
+ bf_init(ctx->bf_ctx, r);
+ bf_set_nan(r);
+ break;
+ }
+ return r;
+}
+
+#ifdef CONFIG_BIGNUM
+/* return NULL if invalid type */
+static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val)
+{
+ uint32_t tag;
+ JSBigDecimal *p;
+ bfdec_t *r;
+
+ tag = JS_VALUE_GET_NORM_TAG(val);
+ switch(tag) {
+ case JS_TAG_BIG_DECIMAL:
+ p = JS_VALUE_GET_PTR(val);
+ r = &p->num;
+ break;
+ default:
+ JS_ThrowTypeError(ctx, "bigdecimal expected");
+ r = NULL;
+ break;
+ }
+ return r;
+}
+
+static JSValue JS_NewBigFloat(JSContext *ctx)
+{
+ JSBigFloat *p;
+ p = js_malloc(ctx, sizeof(*p));
+ if (!p)
+ return JS_EXCEPTION;
+ p->header.ref_count = 1;
+ bf_init(ctx->bf_ctx, &p->num);
+ return JS_MKPTR(JS_TAG_BIG_FLOAT, p);
+}
+
+static JSValue JS_NewBigDecimal(JSContext *ctx)
+{
+ JSBigDecimal *p;
+ p = js_malloc(ctx, sizeof(*p));
+ if (!p)
+ return JS_EXCEPTION;
+ p->header.ref_count = 1;
+ bfdec_init(ctx->bf_ctx, &p->num);
+ return JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
+}
+
/* must be kept in sync with JSOverloadableOperatorEnum */
/* XXX: use atoms ? */
static const char js_overloadable_operator_names[JS_OVOP_COUNT][4] = {
@@ -12508,7 +12682,7 @@ static JSObject *find_binary_op(JSBinaryOperatorDef *def,
/* return -1 if exception, 0 if no operator overloading, 1 if
overloaded operator called */
-static WARN_UNUSED int js_call_binary_op_fallback(JSContext *ctx,
+static __exception int js_call_binary_op_fallback(JSContext *ctx,
JSValue *pret,
JSValueConst op1,
JSValueConst op2,
@@ -12637,7 +12811,7 @@ static WARN_UNUSED int js_call_binary_op_fallback(JSContext *ctx,
/* try to call the operation on the operatorSet field of 'obj'. Only
used for "/" and "**" on the BigInt prototype in math mode */
-static WARN_UNUSED int js_call_binary_op_simple(JSContext *ctx,
+static __exception int js_call_binary_op_simple(JSContext *ctx,
JSValue *pret,
JSValueConst obj,
JSValueConst op1,
@@ -12694,7 +12868,7 @@ static WARN_UNUSED int js_call_binary_op_simple(JSContext *ctx,
/* return -1 if exception, 0 if no operator overloading, 1 if
overloaded operator called */
-static WARN_UNUSED int js_call_unary_op_fallback(JSContext *ctx,
+static __exception int js_call_unary_op_fallback(JSContext *ctx,
JSValue *pret,
JSValueConst op1,
OPCodeEnum op)
@@ -12741,46 +12915,37 @@ static WARN_UNUSED int js_call_unary_op_fallback(JSContext *ctx,
return -1;
}
-static JSValue throw_bf_exception(JSContext *ctx, int status)
-{
- const char *str;
- if (status & BF_ST_MEM_ERROR)
- return JS_ThrowOutOfMemory(ctx);
- if (status & BF_ST_DIVIDE_ZERO) {
- str = "division by zero";
- } else if (status & BF_ST_INVALID_OP) {
- str = "invalid operation";
- } else {
- str = "integer overflow";
- }
- return JS_ThrowRangeError(ctx, "%s", str);
-}
-
-static int js_unary_arith_bigint(JSContext *ctx,
- JSValue *pres, OPCodeEnum op, JSValue op1)
+static int js_unary_arith_bigfloat(JSContext *ctx,
+ JSValue *pres, OPCodeEnum op, JSValue op1)
{
bf_t a_s, *r, *a;
int ret, v;
JSValue res;
if (op == OP_plus && !is_math_mode(ctx)) {
- JS_ThrowTypeError(ctx, "bigint argument with unary +");
+ JS_ThrowTypeError(ctx, "bigfloat argument with unary +");
JS_FreeValue(ctx, op1);
return -1;
}
- res = JS_NewBigInt(ctx);
+
+ res = JS_NewBigFloat(ctx);
if (JS_IsException(res)) {
JS_FreeValue(ctx, op1);
return -1;
}
- r = JS_GetBigInt(res);
- a = JS_ToBigInt(ctx, &a_s, op1);
+ r = JS_GetBigFloat(res);
+ a = JS_ToBigFloat(ctx, &a_s, op1);
+ if (!a) {
+ JS_FreeValue(ctx, res);
+ JS_FreeValue(ctx, op1);
+ return -1;
+ }
ret = 0;
switch(op) {
case OP_inc:
case OP_dec:
v = 2 * (op - OP_dec) - 1;
- ret = bf_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
+ ret = bf_add_si(r, a, v, ctx->fp_env.prec, ctx->fp_env.flags);
break;
case OP_plus:
ret = bf_set(r, a);
@@ -12789,66 +12954,65 @@ static int js_unary_arith_bigint(JSContext *ctx,
ret = bf_set(r, a);
bf_neg(r);
break;
- case OP_not:
- ret = bf_add_si(r, a, 1, BF_PREC_INF, BF_RNDZ);
- bf_neg(r);
- break;
default:
abort();
}
- JS_FreeBigInt(ctx, a, &a_s);
+ if (a == &a_s)
+ bf_delete(a);
JS_FreeValue(ctx, op1);
- if (unlikely(ret)) {
+ if (unlikely(ret & BF_ST_MEM_ERROR)) {
JS_FreeValue(ctx, res);
throw_bf_exception(ctx, ret);
return -1;
}
- res = JS_CompactBigInt(ctx, res);
*pres = res;
return 0;
}
-static int js_unary_arith_bigfloat(JSContext *ctx,
- JSValue *pres, OPCodeEnum op, JSValue op1)
+static int js_unary_arith_bigdecimal(JSContext *ctx,
+ JSValue *pres, OPCodeEnum op, JSValue op1)
{
- bf_t a_s, *r, *a;
+ bfdec_t *r, *a;
int ret, v;
JSValue res;
if (op == OP_plus && !is_math_mode(ctx)) {
- JS_ThrowTypeError(ctx, "bigfloat argument with unary +");
+ JS_ThrowTypeError(ctx, "bigdecimal argument with unary +");
JS_FreeValue(ctx, op1);
return -1;
}
- res = JS_NewBigFloat(ctx);
+ res = JS_NewBigDecimal(ctx);
if (JS_IsException(res)) {
JS_FreeValue(ctx, op1);
return -1;
}
- r = JS_GetBigFloat(res);
- a = JS_ToBigFloat(ctx, &a_s, op1);
+ r = JS_GetBigDecimal(res);
+ a = JS_ToBigDecimal(ctx, op1);
+ if (!a) {
+ JS_FreeValue(ctx, res);
+ JS_FreeValue(ctx, op1);
+ return -1;
+ }
ret = 0;
switch(op) {
case OP_inc:
case OP_dec:
v = 2 * (op - OP_dec) - 1;
- ret = bf_add_si(r, a, v, ctx->fp_env.prec, ctx->fp_env.flags);
+ ret = bfdec_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
break;
case OP_plus:
- ret = bf_set(r, a);
+ ret = bfdec_set(r, a);
break;
case OP_neg:
- ret = bf_set(r, a);
- bf_neg(r);
+ ret = bfdec_set(r, a);
+ bfdec_neg(r);
break;
default:
abort();
}
- if (a == &a_s)
- bf_delete(a);
JS_FreeValue(ctx, op1);
- if (unlikely(ret & BF_ST_MEM_ERROR)) {
+ if (unlikely(ret)) {
JS_FreeValue(ctx, res);
throw_bf_exception(ctx, ret);
return -1;
@@ -12857,67 +13021,81 @@ static int js_unary_arith_bigfloat(JSContext *ctx,
return 0;
}
-static int js_unary_arith_bigdecimal(JSContext *ctx,
- JSValue *pres, OPCodeEnum op, JSValue op1)
+#endif /* CONFIG_BIGNUM */
+
+static int js_unary_arith_bigint(JSContext *ctx,
+ JSValue *pres, OPCodeEnum op, JSValue op1)
{
- bfdec_t *r, *a;
+ bf_t a_s, *r, *a;
int ret, v;
JSValue res;
if (op == OP_plus && !is_math_mode(ctx)) {
- JS_ThrowTypeError(ctx, "bigdecimal argument with unary +");
+ JS_ThrowTypeError(ctx, "bigint argument with unary +");
JS_FreeValue(ctx, op1);
return -1;
}
-
- res = JS_NewBigDecimal(ctx);
+ res = JS_NewBigInt(ctx);
if (JS_IsException(res)) {
JS_FreeValue(ctx, op1);
return -1;
}
- r = JS_GetBigDecimal(res);
- a = JS_ToBigDecimal(ctx, op1);
+ r = JS_GetBigInt(res);
+ a = JS_ToBigInt(ctx, &a_s, op1);
+ if (!a) {
+ JS_FreeValue(ctx, res);
+ JS_FreeValue(ctx, op1);
+ return -1;
+ }
ret = 0;
switch(op) {
case OP_inc:
case OP_dec:
v = 2 * (op - OP_dec) - 1;
- ret = bfdec_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
+ ret = bf_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
break;
case OP_plus:
- ret = bfdec_set(r, a);
+ ret = bf_set(r, a);
break;
case OP_neg:
- ret = bfdec_set(r, a);
- bfdec_neg(r);
+ ret = bf_set(r, a);
+ bf_neg(r);
+ break;
+ case OP_not:
+ ret = bf_add_si(r, a, 1, BF_PREC_INF, BF_RNDZ);
+ bf_neg(r);
break;
default:
abort();
}
+ JS_FreeBigInt(ctx, a, &a_s);
JS_FreeValue(ctx, op1);
if (unlikely(ret)) {
JS_FreeValue(ctx, res);
throw_bf_exception(ctx, ret);
return -1;
}
+ res = JS_CompactBigInt(ctx, res);
*pres = res;
return 0;
}
-static no_inline WARN_UNUSED int js_unary_arith_slow(JSContext *ctx,
+static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
JSValue *sp,
OPCodeEnum op)
{
- JSValue op1, val;
- int v, ret;
+ JSValue op1;
+ int v;
uint32_t tag;
op1 = sp[-1];
/* fast path for float64 */
if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)))
goto handle_float64;
+#ifdef CONFIG_BIGNUM
if (JS_IsObject(op1)) {
- ret = js_call_unary_op_fallback(ctx, &val, op1, op);
+ JSValue val;
+ int ret = js_call_unary_op_fallback(ctx, &val, op1, op);
if (ret < 0)
return -1;
if (ret) {
@@ -12926,7 +13104,7 @@ static no_inline WARN_UNUSED int js_unary_arith_slow(JSContext *ctx,
return 0;
}
}
-
+#endif
op1 = JS_ToNumericFree(ctx, op1);
if (JS_IsException(op1))
goto exception;
@@ -12946,7 +13124,7 @@ static no_inline WARN_UNUSED int js_unary_arith_slow(JSContext *ctx,
break;
case OP_neg:
if (v64 == 0) {
- sp[-1] = __JS_NewFloat64(ctx, -0.0);
+ sp[-1] = JS_NewFloat64(ctx, -0.0);
return 0;
} else {
v64 = -v64;
@@ -12963,6 +13141,7 @@ static no_inline WARN_UNUSED int js_unary_arith_slow(JSContext *ctx,
if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, op, op1))
goto exception;
break;
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
if (ctx->rt->bigfloat_ops.unary_arith(ctx, sp - 1, op, op1))
goto exception;
@@ -12971,6 +13150,7 @@ static no_inline WARN_UNUSED int js_unary_arith_slow(JSContext *ctx,
if (ctx->rt->bigdecimal_ops.unary_arith(ctx, sp - 1, op, op1))
goto exception;
break;
+#endif
default:
handle_float64:
{
@@ -12992,7 +13172,7 @@ static no_inline WARN_UNUSED int js_unary_arith_slow(JSContext *ctx,
default:
abort();
}
- sp[-1] = __JS_NewFloat64(ctx, d);
+ sp[-1] = JS_NewFloat64(ctx, d);
}
break;
}
@@ -13002,7 +13182,7 @@ static no_inline WARN_UNUSED int js_unary_arith_slow(JSContext *ctx,
return -1;
}
-static WARN_UNUSED int js_post_inc_slow(JSContext *ctx,
+static __exception int js_post_inc_slow(JSContext *ctx,
JSValue *sp, OPCodeEnum op)
{
JSValue op1;
@@ -13021,12 +13201,13 @@ static WARN_UNUSED int js_post_inc_slow(JSContext *ctx,
static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
{
- JSValue op1, val;
- int ret;
+ JSValue op1;
op1 = sp[-1];
+#ifdef CONFIG_BIGNUM
if (JS_IsObject(op1)) {
- ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not);
+ JSValue val;
+ int ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not);
if (ret < 0)
return -1;
if (ret) {
@@ -13035,7 +13216,7 @@ static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
return 0;
}
}
-
+#endif
op1 = JS_ToNumericFree(ctx, op1);
if (JS_IsException(op1))
goto exception;
@@ -13054,67 +13235,6 @@ static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
return -1;
}
-static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op,
- JSValue *pres, JSValue op1, JSValue op2)
-{
- bf_t a_s, b_s, *r, *a, *b;
- int ret;
- JSValue res;
-
- res = JS_NewBigFloat(ctx);
- if (JS_IsException(res)) {
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- return -1;
- }
- r = JS_GetBigFloat(res);
- a = JS_ToBigFloat(ctx, &a_s, op1);
- b = JS_ToBigFloat(ctx, &b_s, op2);
- bf_init(ctx->bf_ctx, r);
- switch(op) {
- case OP_add:
- ret = bf_add(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
- break;
- case OP_sub:
- ret = bf_sub(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
- break;
- case OP_mul:
- ret = bf_mul(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
- break;
- case OP_div:
- ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
- break;
- case OP_math_mod:
- /* Euclidian remainder */
- ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
- BF_DIVREM_EUCLIDIAN);
- break;
- case OP_mod:
- ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
- BF_RNDZ);
- break;
- case OP_pow:
- ret = bf_pow(r, a, b, ctx->fp_env.prec,
- ctx->fp_env.flags | BF_POW_JS_QUIRKS);
- break;
- default:
- abort();
- }
- if (a == &a_s)
- bf_delete(a);
- if (b == &b_s)
- bf_delete(b);
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- if (unlikely(ret & BF_ST_MEM_ERROR)) {
- JS_FreeValue(ctx, res);
- throw_bf_exception(ctx, ret);
- return -1;
- }
- *pres = res;
- return 0;
-}
-
static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
JSValue *pres, JSValue op1, JSValue op2)
{
@@ -13156,11 +13276,13 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
goto math_mode_div_pow;
}
break;
+#ifdef CONFIG_BIGNUM
case OP_math_mod:
/* Euclidian remainder */
ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
BF_DIVREM_EUCLIDIAN) & BF_ST_INVALID_OP;
break;
+#endif
case OP_mod:
ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
BF_RNDZ) & BF_ST_INVALID_OP;
@@ -13171,6 +13293,7 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
ret = BF_ST_INVALID_OP;
} else {
math_mode_div_pow:
+#ifdef CONFIG_BIGNUM
JS_FreeValue(ctx, res);
ret = js_call_binary_op_simple(ctx, &res, ctx->class_proto[JS_CLASS_BIG_INT], op1, op2, op);
if (ret != 0) {
@@ -13211,6 +13334,9 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
}
*pres = res;
return 0;
+#else
+ abort();
+#endif
}
} else {
ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUIRKS);
@@ -13270,6 +13396,79 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
return -1;
}
+#ifdef CONFIG_BIGNUM
+static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op,
+ JSValue *pres, JSValue op1, JSValue op2)
+{
+ bf_t a_s, b_s, *r, *a, *b;
+ int ret;
+ JSValue res;
+
+ res = JS_NewBigFloat(ctx);
+ if (JS_IsException(res))
+ goto fail;
+ r = JS_GetBigFloat(res);
+ a = JS_ToBigFloat(ctx, &a_s, op1);
+ if (!a) {
+ JS_FreeValue(ctx, res);
+ goto fail;
+ }
+ b = JS_ToBigFloat(ctx, &b_s, op2);
+ if (!b) {
+ if (a == &a_s)
+ bf_delete(a);
+ JS_FreeValue(ctx, res);
+ goto fail;
+ }
+ bf_init(ctx->bf_ctx, r);
+ switch(op) {
+ case OP_add:
+ ret = bf_add(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
+ break;
+ case OP_sub:
+ ret = bf_sub(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
+ break;
+ case OP_mul:
+ ret = bf_mul(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
+ break;
+ case OP_div:
+ ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
+ break;
+ case OP_math_mod:
+ /* Euclidian remainder */
+ ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
+ BF_DIVREM_EUCLIDIAN);
+ break;
+ case OP_mod:
+ ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
+ BF_RNDZ);
+ break;
+ case OP_pow:
+ ret = bf_pow(r, a, b, ctx->fp_env.prec,
+ ctx->fp_env.flags | BF_POW_JS_QUIRKS);
+ break;
+ default:
+ abort();
+ }
+ if (a == &a_s)
+ bf_delete(a);
+ if (b == &b_s)
+ bf_delete(b);
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ if (unlikely(ret & BF_ST_MEM_ERROR)) {
+ JS_FreeValue(ctx, res);
+ throw_bf_exception(ctx, ret);
+ return -1;
+ }
+ *pres = res;
+ return 0;
+ fail:
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ return -1;
+}
+
/* b must be a positive integer */
static int js_bfdec_pow(bfdec_t *r, const bfdec_t *a, const bfdec_t *b)
{
@@ -13356,13 +13555,13 @@ static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op,
JS_FreeValue(ctx, op2);
return -1;
}
+#endif /* CONFIG_BIGNUM */
-static no_inline WARN_UNUSED int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
+static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
OPCodeEnum op)
{
- JSValue op1, op2, res;
+ JSValue op1, op2;
uint32_t tag1, tag2;
- int ret;
double d1, d2;
op1 = sp[-2];
@@ -13376,12 +13575,14 @@ static no_inline WARN_UNUSED int js_binary_arith_slow(JSContext *ctx, JSValue *s
goto handle_float64;
}
+#ifdef CONFIG_BIGNUM
/* try to call an overloaded operator */
if ((tag1 == JS_TAG_OBJECT &&
(tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
(tag2 == JS_TAG_OBJECT &&
(tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
- ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
+ JSValue res;
+ int ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
if (ret != 0) {
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
@@ -13393,6 +13594,7 @@ static no_inline WARN_UNUSED int js_binary_arith_slow(JSContext *ctx, JSValue *s
}
}
}
+#endif
op1 = JS_ToNumericFree(ctx, op1);
if (JS_IsException(op1)) {
@@ -13422,15 +13624,16 @@ static no_inline WARN_UNUSED int js_binary_arith_slow(JSContext *ctx, JSValue *s
(v < -MAX_SAFE_INTEGER || v > MAX_SAFE_INTEGER))
goto handle_bigint;
if (v == 0 && (v1 | v2) < 0) {
- sp[-2] = __JS_NewFloat64(ctx, -0.0);
+ sp[-2] = JS_NewFloat64(ctx, -0.0);
return 0;
}
break;
case OP_div:
if (is_math_mode(ctx))
goto handle_bigint;
- sp[-2] = __JS_NewFloat64(ctx, (double)v1 / (double)v2);
+ sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2);
return 0;
+#ifdef CONFIG_BIGNUM
case OP_math_mod:
if (unlikely(v2 == 0)) {
throw_bf_exception(ctx, BF_ST_DIVIDE_ZERO);
@@ -13444,6 +13647,7 @@ static no_inline WARN_UNUSED int js_binary_arith_slow(JSContext *ctx, JSValue *s
v += v2;
}
break;
+#endif
case OP_mod:
if (v1 < 0 || v2 <= 0) {
sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2));
@@ -13464,13 +13668,17 @@ static no_inline WARN_UNUSED int js_binary_arith_slow(JSContext *ctx, JSValue *s
abort();
}
sp[-2] = JS_NewInt64(ctx, v);
- } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
+ } else
+#ifdef CONFIG_BIGNUM
+ if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
if (ctx->rt->bigdecimal_ops.binary_arith(ctx, op, sp - 2, op1, op2))
goto exception;
} else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
if (ctx->rt->bigfloat_ops.binary_arith(ctx, op, sp - 2, op1, op2))
goto exception;
- } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
+ } else
+#endif
+ if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
handle_bigint:
if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
goto exception;
@@ -13499,6 +13707,7 @@ static no_inline WARN_UNUSED int js_binary_arith_slow(JSContext *ctx, JSValue *s
case OP_mod:
dr = fmod(d1, d2);
break;
+#ifdef CONFIG_BIGNUM
case OP_math_mod:
d2 = fabs(d2);
dr = fmod(d1, d2);
@@ -13506,13 +13715,14 @@ static no_inline WARN_UNUSED int js_binary_arith_slow(JSContext *ctx, JSValue *s
if (dr < 0)
dr += d2;
break;
+#endif
case OP_pow:
dr = js_pow(d1, d2);
break;
default:
abort();
}
- sp[-2] = __JS_NewFloat64(ctx, dr);
+ sp[-2] = JS_NewFloat64(ctx, dr);
}
return 0;
exception:
@@ -13521,11 +13731,10 @@ static no_inline WARN_UNUSED int js_binary_arith_slow(JSContext *ctx, JSValue *s
return -1;
}
-static no_inline WARN_UNUSED int js_add_slow(JSContext *ctx, JSValue *sp)
+static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
{
- JSValue op1, op2, res;
+ JSValue op1, op2;
uint32_t tag1, tag2;
- int ret;
op1 = sp[-2];
op2 = sp[-1];
@@ -13537,11 +13746,12 @@ static no_inline WARN_UNUSED int js_add_slow(JSContext *ctx, JSValue *sp)
double d1, d2;
d1 = JS_VALUE_GET_FLOAT64(op1);
d2 = JS_VALUE_GET_FLOAT64(op2);
- sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
+ sp[-2] = JS_NewFloat64(ctx, d1 + d2);
return 0;
}
if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) {
+#ifdef CONFIG_BIGNUM
/* try to call an overloaded operator */
if ((tag1 == JS_TAG_OBJECT &&
(tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED &&
@@ -13549,8 +13759,9 @@ static no_inline WARN_UNUSED int js_add_slow(JSContext *ctx, JSValue *sp)
(tag2 == JS_TAG_OBJECT &&
(tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED &&
tag1 != JS_TAG_STRING))) {
- ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add,
- FALSE, HINT_NONE);
+ JSValue res;
+ int ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add,
+ FALSE, HINT_NONE);
if (ret != 0) {
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
@@ -13562,7 +13773,7 @@ static no_inline WARN_UNUSED int js_add_slow(JSContext *ctx, JSValue *sp)
}
}
}
-
+#endif
op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
if (JS_IsException(op1)) {
JS_FreeValue(ctx, op2);
@@ -13605,13 +13816,17 @@ static no_inline WARN_UNUSED int js_add_slow(JSContext *ctx, JSValue *sp)
v2 = JS_VALUE_GET_INT(op2);
v = (int64_t)v1 + (int64_t)v2;
sp[-2] = JS_NewInt64(ctx, v);
- } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
+ } else
+#ifdef CONFIG_BIGNUM
+ if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
if (ctx->rt->bigdecimal_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
goto exception;
} else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
if (ctx->rt->bigfloat_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
goto exception;
- } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
+ } else
+#endif
+ if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
handle_bigint:
if (ctx->rt->bigint_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
goto exception;
@@ -13626,7 +13841,7 @@ static no_inline WARN_UNUSED int js_add_slow(JSContext *ctx, JSValue *sp)
goto exception;
if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2))
goto handle_bigint;
- sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
+ sp[-2] = JS_NewFloat64(ctx, d1 + d2);
}
return 0;
exception:
@@ -13635,12 +13850,11 @@ static no_inline WARN_UNUSED int js_add_slow(JSContext *ctx, JSValue *sp)
return -1;
}
-static no_inline WARN_UNUSED int js_binary_logic_slow(JSContext *ctx,
+static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
JSValue *sp,
OPCodeEnum op)
{
- JSValue op1, op2, res;
- int ret;
+ JSValue op1, op2;
uint32_t tag1, tag2;
uint32_t v1, v2, r;
@@ -13649,12 +13863,14 @@ static no_inline WARN_UNUSED int js_binary_logic_slow(JSContext *ctx,
tag1 = JS_VALUE_GET_NORM_TAG(op1);
tag2 = JS_VALUE_GET_NORM_TAG(op2);
+#ifdef CONFIG_BIGNUM
/* try to call an overloaded operator */
if ((tag1 == JS_TAG_OBJECT &&
(tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
(tag2 == JS_TAG_OBJECT &&
(tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
- ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
+ JSValue res;
+ int ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
if (ret != 0) {
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
@@ -13666,6 +13882,7 @@ static no_inline WARN_UNUSED int js_binary_logic_slow(JSContext *ctx,
}
}
}
+#endif
op1 = JS_ToNumericFree(ctx, op1);
if (JS_IsException(op1)) {
@@ -13776,6 +13993,7 @@ static int js_compare_bigfloat(JSContext *ctx, OPCodeEnum op,
return res;
}
+#ifdef CONFIG_BIGNUM
static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op,
JSValue op1, JSValue op2)
{
@@ -13795,8 +14013,8 @@ static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op,
JS_FreeValue(ctx, op1);
return -1;
}
- a = JS_ToBigDecimal(ctx, op1);
- b = JS_ToBigDecimal(ctx, op2);
+ a = JS_ToBigDecimal(ctx, op1); /* cannot fail */
+ b = JS_ToBigDecimal(ctx, op2); /* cannot fail */
switch(op) {
case OP_lt:
@@ -13821,11 +14039,12 @@ static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op,
JS_FreeValue(ctx, op2);
return res;
}
+#endif /* !CONFIG_BIGNUM */
static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
OPCodeEnum op)
{
- JSValue op1, op2, ret;
+ JSValue op1, op2;
int res;
uint32_t tag1, tag2;
@@ -13833,11 +14052,13 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
op2 = sp[-1];
tag1 = JS_VALUE_GET_NORM_TAG(op1);
tag2 = JS_VALUE_GET_NORM_TAG(op2);
+#ifdef CONFIG_BIGNUM
/* try to call an overloaded operator */
if ((tag1 == JS_TAG_OBJECT &&
(tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
(tag2 == JS_TAG_OBJECT &&
(tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
+ JSValue ret;
res = js_call_binary_op_fallback(ctx, &ret, op1, op2, op,
FALSE, HINT_NUMBER);
if (res != 0) {
@@ -13851,6 +14072,7 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
}
}
}
+#endif
op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);
if (JS_IsException(op1)) {
JS_FreeValue(ctx, op2);
@@ -13925,6 +14147,7 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
tag1 = JS_VALUE_GET_NORM_TAG(op1);
tag2 = JS_VALUE_GET_NORM_TAG(op2);
+#ifdef CONFIG_BIGNUM
if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
res = ctx->rt->bigdecimal_ops.compare(ctx, op, op1, op2);
if (res < 0)
@@ -13933,7 +14156,9 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
res = ctx->rt->bigfloat_ops.compare(ctx, op, op1, op2);
if (res < 0)
goto exception;
- } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
+ } else
+#endif
+ if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
res = ctx->rt->bigint_ops.compare(ctx, op, op1, op2);
if (res < 0)
goto exception;
@@ -13981,14 +14206,20 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
static BOOL tag_is_number(uint32_t tag)
{
return (tag == JS_TAG_INT || tag == JS_TAG_BIG_INT ||
- tag == JS_TAG_FLOAT64 || tag == JS_TAG_BIG_FLOAT ||
- tag == JS_TAG_BIG_DECIMAL);
+ tag == JS_TAG_FLOAT64
+#ifdef CONFIG_BIGNUM
+ || tag == JS_TAG_BIG_FLOAT || tag == JS_TAG_BIG_DECIMAL
+#endif
+ );
}
-static no_inline WARN_UNUSED int js_eq_slow(JSContext *ctx, JSValue *sp,
+static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
BOOL is_neq)
{
- JSValue op1, op2, ret;
+ JSValue op1, op2;
+#ifdef CONFIG_BIGNUM
+ JSValue ret;
+#endif
int res;
uint32_t tag1, tag2;
@@ -14016,7 +14247,9 @@ static no_inline WARN_UNUSED int js_eq_slow(JSContext *ctx, JSValue *sp,
d2 = JS_VALUE_GET_INT(op2);
}
res = (d1 == d2);
- } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
+ } else
+#ifdef CONFIG_BIGNUM
+ if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
res = ctx->rt->bigdecimal_ops.compare(ctx, OP_eq, op1, op2);
if (res < 0)
goto exception;
@@ -14024,12 +14257,15 @@ static no_inline WARN_UNUSED int js_eq_slow(JSContext *ctx, JSValue *sp,
res = ctx->rt->bigfloat_ops.compare(ctx, OP_eq, op1, op2);
if (res < 0)
goto exception;
- } else {
+ } else
+#endif
+ {
res = ctx->rt->bigint_ops.compare(ctx, OP_eq, op1, op2);
if (res < 0)
goto exception;
}
} else if (tag1 == tag2) {
+#ifdef CONFIG_BIGNUM
if (tag1 == JS_TAG_OBJECT) {
/* try the fallback operator */
res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
@@ -14046,6 +14282,7 @@ static no_inline WARN_UNUSED int js_eq_slow(JSContext *ctx, JSValue *sp,
}
}
}
+#endif
res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
} else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||
(tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {
@@ -14082,7 +14319,7 @@ static no_inline WARN_UNUSED int js_eq_slow(JSContext *ctx, JSValue *sp,
goto exception;
}
}
- res = js_strict_eq(ctx, op1, op2);
+ res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
} else if (tag1 == JS_TAG_BOOL) {
op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));
goto redo;
@@ -14093,7 +14330,7 @@ static no_inline WARN_UNUSED int js_eq_slow(JSContext *ctx, JSValue *sp,
(tag_is_number(tag2) || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) ||
(tag2 == JS_TAG_OBJECT &&
(tag_is_number(tag1) || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL))) {
-
+#ifdef CONFIG_BIGNUM
/* try the fallback operator */
res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
is_neq ? OP_neq : OP_eq,
@@ -14108,7 +14345,7 @@ static no_inline WARN_UNUSED int js_eq_slow(JSContext *ctx, JSValue *sp,
return 0;
}
}
-
+#endif
op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
if (JS_IsException(op1)) {
JS_FreeValue(ctx, op2);
@@ -14180,6 +14417,7 @@ static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp)
return -1;
}
+#ifdef CONFIG_BIGNUM
static JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a,
int64_t exponent)
{
@@ -14197,7 +14435,7 @@ static JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a,
if (ret & BF_ST_MEM_ERROR)
return JS_ThrowOutOfMemory(ctx);
else
- return __JS_NewFloat64(ctx, d);
+ return JS_NewFloat64(ctx, d);
}
static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp)
@@ -14214,8 +14452,10 @@ static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp)
op1 = sp[-2];
op2 = sp[-1];
a = JS_ToBigFloat(ctx, &a_s, op1);
- if (!a)
+ if (!a) {
+ JS_FreeValue(ctx, res);
return -1;
+ }
if (JS_IsBigInt(ctx, op2)) {
ret = JS_ToBigInt64(ctx, &e, op2);
} else {
@@ -14236,395 +14476,7 @@ static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp)
sp[-2] = res;
return 0;
}
-
-#else /* !CONFIG_BIGNUM */
-
-static JSValue JS_ThrowUnsupportedBigint(JSContext *ctx)
-{
- return JS_ThrowTypeError(ctx, "bigint is not supported");
-}
-
-JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
-{
- return JS_ThrowUnsupportedBigint(ctx);
-}
-
-JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
-{
- return JS_ThrowUnsupportedBigint(ctx);
-}
-
-int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
-{
- JS_ThrowUnsupportedBigint(ctx);
- *pres = 0;
- return -1;
-}
-
-static no_inline warn_unused int js_unary_arith_slow(JSContext *ctx,
- JSValue *sp,
- OPCodeEnum op)
-{
- JSValue op1;
- double d;
-
- op1 = sp[-1];
- if (unlikely(JS_ToFloat64Free(ctx, &d, op1))) {
- sp[-1] = JS_UNDEFINED;
- return -1;
- }
- switch(op) {
- case OP_inc:
- d++;
- break;
- case OP_dec:
- d--;
- break;
- case OP_plus:
- break;
- case OP_neg:
- d = -d;
- break;
- default:
- abort();
- }
- sp[-1] = JS_NewFloat64(ctx, d);
- return 0;
-}
-
-/* specific case necessary for correct return value semantics */
-static warn_unused int js_post_inc_slow(JSContext *ctx,
- JSValue *sp, OPCodeEnum op)
-{
- JSValue op1;
- double d, r;
-
- op1 = sp[-1];
- if (unlikely(JS_ToFloat64Free(ctx, &d, op1))) {
- sp[-1] = JS_UNDEFINED;
- return -1;
- }
- r = d + 2 * (op - OP_post_dec) - 1;
- sp[0] = JS_NewFloat64(ctx, r);
- sp[-1] = JS_NewFloat64(ctx, d);
- return 0;
-}
-
-static no_inline warn_unused int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
- OPCodeEnum op)
-{
- JSValue op1, op2;
- double d1, d2, r;
-
- op1 = sp[-2];
- op2 = sp[-1];
- if (unlikely(JS_ToFloat64Free(ctx, &d1, op1))) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- if (unlikely(JS_ToFloat64Free(ctx, &d2, op2))) {
- goto exception;
- }
- switch(op) {
- case OP_sub:
- r = d1 - d2;
- break;
- case OP_mul:
- r = d1 * d2;
- break;
- case OP_div:
- r = d1 / d2;
- break;
- case OP_mod:
- r = fmod(d1, d2);
- break;
- case OP_pow:
- r = js_pow(d1, d2);
- break;
- default:
- abort();
- }
- sp[-2] = JS_NewFloat64(ctx, r);
- return 0;
- exception:
- sp[-2] = JS_UNDEFINED;
- sp[-1] = JS_UNDEFINED;
- return -1;
-}
-
-static no_inline warn_unused int js_add_slow(JSContext *ctx, JSValue *sp)
-{
- JSValue op1, op2;
- uint32_t tag1, tag2;
-
- op1 = sp[-2];
- op2 = sp[-1];
- tag1 = JS_VALUE_GET_TAG(op1);
- tag2 = JS_VALUE_GET_TAG(op2);
- if ((tag1 == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag1)) &&
- (tag2 == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag2))) {
- goto add_numbers;
- } else {
- op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
- if (JS_IsException(op1)) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
- if (JS_IsException(op2)) {
- JS_FreeValue(ctx, op1);
- goto exception;
- }
- tag1 = JS_VALUE_GET_TAG(op1);
- tag2 = JS_VALUE_GET_TAG(op2);
- if (tag1 == JS_TAG_STRING || tag2 == JS_TAG_STRING) {
- sp[-2] = JS_ConcatString(ctx, op1, op2);
- if (JS_IsException(sp[-2]))
- goto exception;
- } else {
- double d1, d2;
- add_numbers:
- if (JS_ToFloat64Free(ctx, &d1, op1)) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- if (JS_ToFloat64Free(ctx, &d2, op2))
- goto exception;
- sp[-2] = JS_NewFloat64(ctx, d1 + d2);
- }
- }
- return 0;
- exception:
- sp[-2] = JS_UNDEFINED;
- sp[-1] = JS_UNDEFINED;
- return -1;
-}
-
-static no_inline warn_unused int js_binary_logic_slow(JSContext *ctx,
- JSValue *sp,
- OPCodeEnum op)
-{
- JSValue op1, op2;
- uint32_t v1, v2, r;
-
- op1 = sp[-2];
- op2 = sp[-1];
- if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
- goto exception;
- switch(op) {
- case OP_shl:
- r = v1 << (v2 & 0x1f);
- break;
- case OP_sar:
- r = (int)v1 >> (v2 & 0x1f);
- break;
- case OP_and:
- r = v1 & v2;
- break;
- case OP_or:
- r = v1 | v2;
- break;
- case OP_xor:
- r = v1 ^ v2;
- break;
- default:
- abort();
- }
- sp[-2] = JS_NewInt32(ctx, r);
- return 0;
- exception:
- sp[-2] = JS_UNDEFINED;
- sp[-1] = JS_UNDEFINED;
- return -1;
-}
-
-static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
-{
- int32_t v1;
-
- if (unlikely(JS_ToInt32Free(ctx, &v1, sp[-1]))) {
- sp[-1] = JS_UNDEFINED;
- return -1;
- }
- sp[-1] = JS_NewInt32(ctx, ~v1);
- return 0;
-}
-
-static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
- OPCodeEnum op)
-{
- JSValue op1, op2;
- int res;
-
- op1 = sp[-2];
- op2 = sp[-1];
- op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);
- if (JS_IsException(op1)) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER);
- if (JS_IsException(op2)) {
- JS_FreeValue(ctx, op1);
- goto exception;
- }
- if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING &&
- JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {
- JSString *p1, *p2;
- p1 = JS_VALUE_GET_STRING(op1);
- p2 = JS_VALUE_GET_STRING(op2);
- res = js_string_compare(ctx, p1, p2);
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- switch(op) {
- case OP_lt:
- res = (res < 0);
- break;
- case OP_lte:
- res = (res <= 0);
- break;
- case OP_gt:
- res = (res > 0);
- break;
- default:
- case OP_gte:
- res = (res >= 0);
- break;
- }
- } else {
- double d1, d2;
- if (JS_ToFloat64Free(ctx, &d1, op1)) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- if (JS_ToFloat64Free(ctx, &d2, op2))
- goto exception;
- switch(op) {
- case OP_lt:
- res = (d1 < d2); /* if NaN return false */
- break;
- case OP_lte:
- res = (d1 <= d2); /* if NaN return false */
- break;
- case OP_gt:
- res = (d1 > d2); /* if NaN return false */
- break;
- default:
- case OP_gte:
- res = (d1 >= d2); /* if NaN return false */
- break;
- }
- }
- sp[-2] = JS_NewBool(ctx, res);
- return 0;
- exception:
- sp[-2] = JS_UNDEFINED;
- sp[-1] = JS_UNDEFINED;
- return -1;
-}
-
-static no_inline warn_unused int js_eq_slow(JSContext *ctx, JSValue *sp,
- BOOL is_neq)
-{
- JSValue op1, op2;
- int tag1, tag2;
- BOOL res;
-
- op1 = sp[-2];
- op2 = sp[-1];
- redo:
- tag1 = JS_VALUE_GET_NORM_TAG(op1);
- tag2 = JS_VALUE_GET_NORM_TAG(op2);
- if (tag1 == tag2 ||
- (tag1 == JS_TAG_INT && tag2 == JS_TAG_FLOAT64) ||
- (tag2 == JS_TAG_INT && tag1 == JS_TAG_FLOAT64)) {
- res = js_strict_eq(ctx, op1, op2);
- } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||
- (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {
- res = TRUE;
- } else if ((tag1 == JS_TAG_STRING && (tag2 == JS_TAG_INT ||
- tag2 == JS_TAG_FLOAT64)) ||
- (tag2 == JS_TAG_STRING && (tag1 == JS_TAG_INT ||
- tag1 == JS_TAG_FLOAT64))) {
- double d1;
- double d2;
- if (JS_ToFloat64Free(ctx, &d1, op1)) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- if (JS_ToFloat64Free(ctx, &d2, op2))
- goto exception;
- res = (d1 == d2);
- } else if (tag1 == JS_TAG_BOOL) {
- op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));
- goto redo;
- } else if (tag2 == JS_TAG_BOOL) {
- op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2));
- goto redo;
- } else if (tag1 == JS_TAG_OBJECT &&
- (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64 || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) {
- op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
- if (JS_IsException(op1)) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- goto redo;
- } else if (tag2 == JS_TAG_OBJECT &&
- (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64 || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL)) {
- op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
- if (JS_IsException(op2)) {
- JS_FreeValue(ctx, op1);
- goto exception;
- }
- goto redo;
- } else {
- /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */
- if ((JS_IsHTMLDDA(ctx, op1) &&
- (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) ||
- (JS_IsHTMLDDA(ctx, op2) &&
- (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) {
- res = TRUE;
- } else {
- res = FALSE;
- }
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- }
- sp[-2] = JS_NewBool(ctx, res ^ is_neq);
- return 0;
- exception:
- sp[-2] = JS_UNDEFINED;
- sp[-1] = JS_UNDEFINED;
- return -1;
-}
-
-static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp)
-{
- JSValue op1, op2;
- uint32_t v1, v2, r;
-
- op1 = sp[-2];
- op2 = sp[-1];
- if (unlikely(JS_ToUint32Free(ctx, &v1, op1))) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- if (unlikely(JS_ToUint32Free(ctx, &v2, op2)))
- goto exception;
- r = v1 >> (v2 & 0x1f);
- sp[-2] = JS_NewUint32(ctx, r);
- return 0;
- exception:
- sp[-2] = JS_UNDEFINED;
- sp[-1] = JS_UNDEFINED;
- return -1;
-}
-
-#endif /* !CONFIG_BIGNUM */
+#endif
/* XXX: Should take JSValueConst arguments */
static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
@@ -14718,7 +14570,6 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
res = (d1 == d2); /* if NaN return false and +0 == -0 */
}
goto done_no_free;
-#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
{
bf_t a_s, *a, b_s, *b;
@@ -14726,8 +14577,8 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
res = FALSE;
break;
}
- a = JS_ToBigFloat(ctx, &a_s, op1);
- b = JS_ToBigFloat(ctx, &b_s, op2);
+ a = JS_ToBigFloat(ctx, &a_s, op1); /* cannot fail */
+ b = JS_ToBigFloat(ctx, &b_s, op2); /* cannot fail */
res = bf_cmp_eq(a, b);
if (a == &a_s)
bf_delete(a);
@@ -14735,6 +14586,7 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
bf_delete(b);
}
break;
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
{
JSBigFloat *p1, *p2;
@@ -14785,9 +14637,16 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
return res;
}
-static BOOL js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2)
+static BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2)
{
- return js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
+ return js_strict_eq2(ctx,
+ JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
+ JS_EQ_STRICT);
+}
+
+BOOL JS_StrictEq(JSContext *ctx, JSValueConst op1, JSValueConst op2)
+{
+ return js_strict_eq(ctx, op1, op2);
}
static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2)
@@ -14797,6 +14656,11 @@ static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2)
JS_EQ_SAME_VALUE);
}
+BOOL JS_SameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2)
+{
+ return js_same_value(ctx, op1, op2);
+}
+
static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2)
{
return js_strict_eq2(ctx,
@@ -14804,16 +14668,21 @@ static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op
JS_EQ_SAME_VALUE_ZERO);
}
+BOOL JS_SameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2)
+{
+ return js_same_value_zero(ctx, op1, op2);
+}
+
static no_inline int js_strict_eq_slow(JSContext *ctx, JSValue *sp,
BOOL is_neq)
{
BOOL res;
- res = js_strict_eq(ctx, sp[-2], sp[-1]);
+ res = js_strict_eq2(ctx, sp[-2], sp[-1], JS_EQ_STRICT);
sp[-2] = JS_NewBool(ctx, res ^ is_neq);
return 0;
}
-static warn_unused int js_operator_in(JSContext *ctx, JSValue *sp)
+static __exception int js_operator_in(JSContext *ctx, JSValue *sp)
{
JSValue op1, op2;
JSAtom atom;
@@ -14839,7 +14708,44 @@ static warn_unused int js_operator_in(JSContext *ctx, JSValue *sp)
return 0;
}
-static warn_unused int js_has_unscopable(JSContext *ctx, JSValueConst obj,
+static __exception int js_operator_private_in(JSContext *ctx, JSValue *sp)
+{
+ JSValue op1, op2;
+ int ret;
+
+ op1 = sp[-2]; /* object */
+ op2 = sp[-1]; /* field name or method function */
+
+ if (JS_VALUE_GET_TAG(op1) != JS_TAG_OBJECT) {
+ JS_ThrowTypeError(ctx, "invalid 'in' operand");
+ return -1;
+ }
+ if (JS_IsObject(op2)) {
+ /* method: use the brand */
+ ret = JS_CheckBrand(ctx, op1, op2);
+ if (ret < 0)
+ return -1;
+ } else {
+ JSAtom atom;
+ JSObject *p;
+ JSShapeProperty *prs;
+ JSProperty *pr;
+ /* field */
+ atom = JS_ValueToAtom(ctx, op2);
+ if (unlikely(atom == JS_ATOM_NULL))
+ return -1;
+ p = JS_VALUE_GET_OBJ(op1);
+ prs = find_own_property(&pr, p, atom);
+ JS_FreeAtom(ctx, atom);
+ ret = (prs != NULL);
+ }
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ sp[-2] = JS_NewBool(ctx, ret);
+ return 0;
+}
+
+static __exception int js_has_unscopable(JSContext *ctx, JSValueConst obj,
JSAtom atom)
{
JSValue arr, val;
@@ -14857,7 +14763,7 @@ static warn_unused int js_has_unscopable(JSContext *ctx, JSValueConst obj,
return ret;
}
-static warn_unused int js_operator_instanceof(JSContext *ctx, JSValue *sp)
+static __exception int js_operator_instanceof(JSContext *ctx, JSValue *sp)
{
JSValue op1, op2;
BOOL ret;
@@ -14873,17 +14779,17 @@ static warn_unused int js_operator_instanceof(JSContext *ctx, JSValue *sp)
return 0;
}
-static warn_unused int js_operator_typeof(JSContext *ctx, JSValueConst op1)
+static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1)
{
JSAtom atom;
uint32_t tag;
tag = JS_VALUE_GET_NORM_TAG(op1);
switch(tag) {
-#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
atom = JS_ATOM_bigint;
break;
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
atom = JS_ATOM_bigfloat;
break;
@@ -14930,7 +14836,7 @@ static warn_unused int js_operator_typeof(JSContext *ctx, JSValueConst op1)
return atom;
}
-static warn_unused int js_operator_delete(JSContext *ctx, JSValue *sp)
+static __exception int js_operator_delete(JSContext *ctx, JSValue *sp)
{
JSValue op1, op2;
JSAtom atom;
@@ -15085,7 +14991,7 @@ static JSValue js_build_mapped_arguments(JSContext *ctx, int argc,
var_ref = get_var_ref(ctx, sf, i, TRUE);
if (!var_ref)
goto fail;
- pr = add_property(ctx, p, JS_AtomFromUInt32(i), JS_PROP_C_W_E | JS_PROP_VARREF);
+ pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E | JS_PROP_VARREF);
if (!pr) {
free_var_ref(ctx->rt, var_ref);
goto fail;
@@ -15137,10 +15043,10 @@ static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst *
static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
{
- JSObject *p;
+ JSObject *p, *p1;
JSPropertyEnum *tab_atom;
int i;
- JSValue enum_obj, obj1;
+ JSValue enum_obj;
JSForInIterator *it;
uint32_t tag, tab_atom_count;
@@ -15163,40 +15069,16 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
it->is_array = FALSE;
it->obj = obj;
it->idx = 0;
- p = JS_VALUE_GET_OBJ(enum_obj);
- p->u.for_in_iterator = it;
+ it->tab_atom = NULL;
+ it->atom_count = 0;
+ it->in_prototype_chain = FALSE;
+ p1 = JS_VALUE_GET_OBJ(enum_obj);
+ p1->u.for_in_iterator = it;
if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
return enum_obj;
- /* fast path: assume no enumerable properties in the prototype chain */
- obj1 = JS_DupValue(ctx, obj);
- for(;;) {
- obj1 = JS_GetPrototypeFree(ctx, obj1);
- if (JS_IsNull(obj1))
- break;
- if (JS_IsException(obj1))
- goto fail;
- if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
- JS_VALUE_GET_OBJ(obj1),
- JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {
- JS_FreeValue(ctx, obj1);
- goto fail;
- }
- js_free_prop_enum(ctx, tab_atom, tab_atom_count);
- if (tab_atom_count != 0) {
- JS_FreeValue(ctx, obj1);
- goto slow_path;
- }
- /* must check for timeout to avoid infinite loop */
- if (js_poll_interrupts(ctx)) {
- JS_FreeValue(ctx, obj1);
- goto fail;
- }
- }
-
p = JS_VALUE_GET_OBJ(obj);
-
if (p->fast_array) {
JSShape *sh;
JSShapeProperty *prs;
@@ -15208,70 +15090,101 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
}
/* for fast arrays, we only store the number of elements */
it->is_array = TRUE;
- it->array_length = p->u.array.count;
+ it->atom_count = p->u.array.count;
} else {
normal_case:
if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
- JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY))
- goto fail;
- for(i = 0; i < tab_atom_count; i++) {
- JS_SetPropertyInternal(ctx, enum_obj, tab_atom[i].atom, JS_NULL, 0);
+ JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
+ JS_FreeValue(ctx, enum_obj);
+ return JS_EXCEPTION;
}
- js_free_prop_enum(ctx, tab_atom, tab_atom_count);
+ it->tab_atom = tab_atom;
+ it->atom_count = tab_atom_count;
}
return enum_obj;
+}
- slow_path:
- /* non enumerable properties hide the enumerables ones in the
- prototype chain */
- obj1 = JS_DupValue(ctx, obj);
+/* obj -> enum_obj */
+static __exception int js_for_in_start(JSContext *ctx, JSValue *sp)
+{
+ sp[-1] = build_for_in_iterator(ctx, sp[-1]);
+ if (JS_IsException(sp[-1]))
+ return -1;
+ return 0;
+}
+
+/* return -1 if exception, 0 if slow case, 1 if the enumeration is finished */
+static __exception int js_for_in_prepare_prototype_chain_enum(JSContext *ctx,
+ JSValueConst enum_obj)
+{
+ JSObject *p;
+ JSForInIterator *it;
+ JSPropertyEnum *tab_atom;
+ uint32_t tab_atom_count, i;
+ JSValue obj1;
+
+ p = JS_VALUE_GET_OBJ(enum_obj);
+ it = p->u.for_in_iterator;
+
+ /* check if there are enumerable properties in the prototype chain (fast path) */
+ obj1 = JS_DupValue(ctx, it->obj);
for(;;) {
+ obj1 = JS_GetPrototypeFree(ctx, obj1);
+ if (JS_IsNull(obj1))
+ break;
+ if (JS_IsException(obj1))
+ goto fail;
if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
JS_VALUE_GET_OBJ(obj1),
- JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
+ JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {
JS_FreeValue(ctx, obj1);
goto fail;
}
- for(i = 0; i < tab_atom_count; i++) {
- JS_DefinePropertyValue(ctx, enum_obj, tab_atom[i].atom, JS_NULL,
- (tab_atom[i].is_enumerable ?
- JS_PROP_ENUMERABLE : 0));
- }
js_free_prop_enum(ctx, tab_atom, tab_atom_count);
- obj1 = JS_GetPrototypeFree(ctx, obj1);
- if (JS_IsNull(obj1))
- break;
- if (JS_IsException(obj1))
- goto fail;
+ if (tab_atom_count != 0) {
+ JS_FreeValue(ctx, obj1);
+ goto slow_path;
+ }
/* must check for timeout to avoid infinite loop */
if (js_poll_interrupts(ctx)) {
JS_FreeValue(ctx, obj1);
goto fail;
}
}
- return enum_obj;
+ JS_FreeValue(ctx, obj1);
+ return 1;
- fail:
- JS_FreeValue(ctx, enum_obj);
- return JS_EXCEPTION;
-}
+ slow_path:
+ /* add the visited properties, even if they are not enumerable */
+ if (it->is_array) {
+ if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
+ JS_VALUE_GET_OBJ(it->obj),
+ JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
+ goto fail;
+ }
+ it->is_array = FALSE;
+ it->tab_atom = tab_atom;
+ it->atom_count = tab_atom_count;
+ }
-/* obj -> enum_obj */
-static warn_unused int js_for_in_start(JSContext *ctx, JSValue *sp)
-{
- sp[-1] = build_for_in_iterator(ctx, sp[-1]);
- if (JS_IsException(sp[-1]))
- return -1;
+ for(i = 0; i < it->atom_count; i++) {
+ if (JS_DefinePropertyValue(ctx, enum_obj, it->tab_atom[i].atom, JS_NULL, JS_PROP_ENUMERABLE) < 0)
+ goto fail;
+ }
return 0;
+ fail:
+ return -1;
}
/* enum_obj -> enum_obj value done */
-static warn_unused int js_for_in_next(JSContext *ctx, JSValue *sp)
+static __exception int js_for_in_next(JSContext *ctx, JSValue *sp)
{
JSValueConst enum_obj;
JSObject *p;
JSAtom prop;
JSForInIterator *it;
+ JSPropertyEnum *tab_atom;
+ uint32_t tab_atom_count;
int ret;
enum_obj = sp[-1];
@@ -15284,28 +15197,68 @@ static warn_unused int js_for_in_next(JSContext *ctx, JSValue *sp)
it = p->u.for_in_iterator;
for(;;) {
- if (it->is_array) {
- if (it->idx >= it->array_length)
- goto done;
- prop = JS_AtomFromUInt32(it->idx);
- it->idx++;
+ if (it->idx >= it->atom_count) {
+ if (JS_IsNull(it->obj) || JS_IsUndefined(it->obj))
+ goto done; /* not an object */
+ /* no more property in the current object: look in the prototype */
+ if (!it->in_prototype_chain) {
+ ret = js_for_in_prepare_prototype_chain_enum(ctx, enum_obj);
+ if (ret < 0)
+ return -1;
+ if (ret)
+ goto done;
+ it->in_prototype_chain = TRUE;
+ }
+ it->obj = JS_GetPrototypeFree(ctx, it->obj);
+ if (JS_IsException(it->obj))
+ return -1;
+ if (JS_IsNull(it->obj))
+ goto done; /* no more prototype */
+
+ /* must check for timeout to avoid infinite loop */
+ if (js_poll_interrupts(ctx))
+ return -1;
+
+ if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
+ JS_VALUE_GET_OBJ(it->obj),
+ JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
+ return -1;
+ }
+ js_free_prop_enum(ctx, it->tab_atom, it->atom_count);
+ it->tab_atom = tab_atom;
+ it->atom_count = tab_atom_count;
+ it->idx = 0;
} else {
- JSShape *sh = p->shape;
- JSShapeProperty *prs;
- if (it->idx >= sh->prop_count)
- goto done;
- prs = get_shape_prop(sh) + it->idx;
- prop = prs->atom;
- it->idx++;
- if (prop == JS_ATOM_NULL || !(prs->flags & JS_PROP_ENUMERABLE))
- continue;
+ if (it->is_array) {
+ prop = __JS_AtomFromUInt32(it->idx);
+ it->idx++;
+ } else {
+ BOOL is_enumerable;
+ prop = it->tab_atom[it->idx].atom;
+ is_enumerable = it->tab_atom[it->idx].is_enumerable;
+ it->idx++;
+ if (it->in_prototype_chain) {
+ /* slow case: we are in the prototype chain */
+ ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(enum_obj), prop);
+ if (ret < 0)
+ return ret;
+ if (ret)
+ continue; /* already visited */
+ /* add to the visited property list */
+ if (JS_DefinePropertyValue(ctx, enum_obj, prop, JS_NULL,
+ JS_PROP_ENUMERABLE) < 0)
+ return -1;
+ }
+ if (!is_enumerable)
+ continue;
+ }
+ /* check if the property was deleted */
+ ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(it->obj), prop);
+ if (ret < 0)
+ return ret;
+ if (ret)
+ break;
}
- /* check if the property was deleted */
- ret = JS_HasProperty(ctx, it->obj, prop);
- if (ret < 0)
- return ret;
- if (ret)
- break;
}
/* return the property */
sp[0] = JS_AtomToValue(ctx, prop);
@@ -15480,7 +15433,7 @@ static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj,
}
/* obj -> enum_rec (3 slots) */
-static warn_unused int js_for_of_start(JSContext *ctx, JSValue *sp,
+static __exception int js_for_of_start(JSContext *ctx, JSValue *sp,
BOOL is_async)
{
JSValue op1, obj, method;
@@ -15501,7 +15454,7 @@ static warn_unused int js_for_of_start(JSContext *ctx, JSValue *sp,
objs. If 'done' is true or in case of exception, 'enum_rec' is set
to undefined. If 'done' is true, 'value' is always set to
undefined. */
-static warn_unused int js_for_of_next(JSContext *ctx, JSValue *sp, int offset)
+static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset)
{
JSValue value = JS_UNDEFINED;
int done = 1;
@@ -15547,7 +15500,7 @@ static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValueConst obj,
return JS_EXCEPTION;
}
-static warn_unused int js_iterator_get_value_done(JSContext *ctx, JSValue *sp)
+static __exception int js_iterator_get_value_done(JSContext *ctx, JSValue *sp)
{
JSValue obj, value;
BOOL done;
@@ -15623,7 +15576,7 @@ static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,
return FALSE;
}
-static warn_unused int js_append_enumerate(JSContext *ctx, JSValue *sp)
+static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp)
{
JSValue iterator, enumobj, method, value;
int is_array_iterator;
@@ -15703,7 +15656,7 @@ exception:
return -1;
}
-static warn_unused int JS_CopyDataProperties(JSContext *ctx,
+static __exception int JS_CopyDataProperties(JSContext *ctx,
JSValueConst target,
JSValueConst source,
JSValueConst excluded,
@@ -15791,7 +15744,7 @@ static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf,
struct list_head *el;
list_for_each(el, &sf->var_ref_list) {
- var_ref = list_entry(el, JSVarRef, header.link);
+ var_ref = list_entry(el, JSVarRef, var_ref_link);
if (var_ref->var_idx == var_idx && var_ref->is_arg == is_arg) {
var_ref->header.ref_count++;
return var_ref;
@@ -15802,15 +15755,29 @@ static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf,
if (!var_ref)
return NULL;
var_ref->header.ref_count = 1;
+ add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
var_ref->is_detached = FALSE;
var_ref->is_arg = is_arg;
var_ref->var_idx = var_idx;
- list_add_tail(&var_ref->header.link, &sf->var_ref_list);
+ list_add_tail(&var_ref->var_ref_link, &sf->var_ref_list);
+ if (sf->js_mode & JS_MODE_ASYNC) {
+ /* The stack frame is detached and may be destroyed at any
+ time so its reference count must be increased. Calling
+ close_var_refs() when destroying the stack frame is not
+ possible because it would change the graph between the GC
+ objects. Another solution could be to temporarily detach
+ the JSVarRef of async functions during the GC. It would
+ have the advantage of allowing the release of unused stack
+ frames in a cycle. */
+ var_ref->async_func = container_of(sf, JSAsyncFunctionState, frame);
+ var_ref->async_func->header.ref_count++;
+ } else {
+ var_ref->async_func = NULL;
+ }
if (is_arg)
var_ref->pvalue = &sf->arg_buf[var_idx];
else
var_ref->pvalue = &sf->var_buf[var_idx];
- var_ref->value = JS_UNDEFINED;
return var_ref;
}
@@ -16041,7 +16008,10 @@ static void close_var_refs(JSRuntime *rt, JSStackFrame *sf)
int var_idx;
list_for_each_safe(el, el1, &sf->var_ref_list) {
- var_ref = list_entry(el, JSVarRef, header.link);
+ var_ref = list_entry(el, JSVarRef, var_ref_link);
+ /* no need to unlink var_ref->var_ref_link as the list is never used afterwards */
+ if (var_ref->async_func)
+ async_func_free(rt, var_ref->async_func);
var_idx = var_ref->var_idx;
if (var_ref->is_arg)
var_ref->value = JS_DupValueRT(rt, sf->arg_buf[var_idx]);
@@ -16050,7 +16020,6 @@ static void close_var_refs(JSRuntime *rt, JSStackFrame *sf)
var_ref->pvalue = &var_ref->value;
/* the reference is no longer to a local variable */
var_ref->is_detached = TRUE;
- add_gc_object(rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
}
}
@@ -16061,14 +16030,15 @@ static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int idx, int is_
int var_idx = idx;
list_for_each_safe(el, el1, &sf->var_ref_list) {
- var_ref = list_entry(el, JSVarRef, header.link);
+ var_ref = list_entry(el, JSVarRef, var_ref_link);
if (var_idx == var_ref->var_idx && var_ref->is_arg == is_arg) {
+ list_del(&var_ref->var_ref_link);
+ if (var_ref->async_func)
+ async_func_free(ctx->rt, var_ref->async_func);
var_ref->value = JS_DupValue(ctx, sf->var_buf[var_idx]);
var_ref->pvalue = &var_ref->value;
- list_del(&var_ref->header.link);
/* the reference is no longer to a local variable */
var_ref->is_detached = TRUE;
- add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
}
}
}
@@ -16125,7 +16095,7 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
arg_buf[i] = JS_UNDEFINED;
sf->arg_count = arg_count;
}
- sf->arg_buf = arg_buf;
+ sf->arg_buf = (JSValue*)arg_buf;
func = p->u.cfunc.c_function;
switch(cproto) {
@@ -16259,9 +16229,10 @@ typedef enum {
OP_SPECIAL_OBJECT_IMPORT_META,
} OPSpecialObjectEnum;
-#define FUNC_RET_AWAIT 0
-#define FUNC_RET_YIELD 1
-#define FUNC_RET_YIELD_STAR 2
+#define FUNC_RET_AWAIT 0
+#define FUNC_RET_YIELD 1
+#define FUNC_RET_YIELD_STAR 2
+#define FUNC_RET_INITIAL_YIELD 3
/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
@@ -16295,7 +16266,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
#include "quickjs-opcode.h"
[ OP_COUNT ... 255 ] = &&case_default
};
-#define SWITCH(pc) goto *dispatch_table[opcode = *(pc)++];
+#define SWITCH(pc) goto *dispatch_table[opcode = *pc++];
#define CASE(op) case_ ## op
#define DEFAULT case_default
#define BREAK SWITCH(pc)
@@ -16338,7 +16309,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
return JS_ThrowTypeError(caller_ctx, "not a function");
}
return call_func(caller_ctx, func_obj, this_obj, argc,
- argv, flags);
+ (JSValueConst *)argv, flags);
}
b = p->u.func.function_bytecode;
@@ -16492,12 +16463,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
int arg = *pc++;
switch(arg) {
case OP_SPECIAL_OBJECT_ARGUMENTS:
- *sp++ = js_build_arguments(ctx, argc, argv);
+ *sp++ = js_build_arguments(ctx, argc, (JSValueConst *)argv);
if (unlikely(JS_IsException(sp[-1])))
goto exception;
break;
case OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS:
- *sp++ = js_build_mapped_arguments(ctx, argc, argv,
+ *sp++ = js_build_mapped_arguments(ctx, argc, (JSValueConst *)argv,
sf, min_int(argc, b->arg_count));
if (unlikely(JS_IsException(sp[-1])))
goto exception;
@@ -16537,7 +16508,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
int first = get_u16(pc);
pc += 2;
- *sp++ = js_build_rest(ctx, first, argc, argv);
+ *sp++ = js_build_rest(ctx, first, argc, (JSValueConst *)argv);
if (unlikely(JS_IsException(sp[-1])))
goto exception;
}
@@ -16770,7 +16741,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
goto exception;
call_argv = sp - call_argc;
for(i = 0; i < call_argc; i++) {
- ret = JS_DefinePropertyValue(ctx, ret_val, JS_AtomFromUInt32(i), call_argv[i],
+ ret = JS_DefinePropertyValue(ctx, ret_val, __JS_AtomFromUInt32(i), call_argv[i],
JS_PROP_C_W_E | JS_PROP_THROW);
call_argv[i] = JS_UNDEFINED;
if (ret < 0) {
@@ -16789,7 +16760,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
magic = get_u16(pc);
pc += 2;
- ret_val = js_function_apply(ctx, sp[-3], 2, &sp[-2], magic);
+ ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst *)&sp[-2], magic);
if (unlikely(JS_IsException(ret_val)))
goto exception;
JS_FreeValue(ctx, sp[-3]);
@@ -16826,8 +16797,15 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
}
BREAK;
CASE(OP_check_brand):
- if (JS_CheckBrand(ctx, sp[-2], sp[-1]) < 0)
- goto exception;
+ {
+ int ret = JS_CheckBrand(ctx, sp[-2], sp[-1]);
+ if (ret < 0)
+ goto exception;
+ if (!ret) {
+ JS_ThrowTypeError(ctx, "invalid brand on object");
+ goto exception;
+ }
+ }
BREAK;
CASE(OP_add_brand):
if (JS_AddBrand(ctx, sp[-2], sp[-1]) < 0)
@@ -16922,7 +16900,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JS_EVAL_TYPE_DIRECT, scope_idx);
} else {
ret_val = JS_Call(ctx, sp[-2], JS_UNDEFINED, len,
- tab);
+ (JSValueConst *)tab);
}
free_arg_list(ctx, tab, len);
if (unlikely(JS_IsException(ret_val)))
@@ -17249,6 +17227,19 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
sp++;
}
BREAK;
+ CASE(OP_get_loc_checkthis):
+ {
+ int idx;
+ idx = get_u16(pc);
+ pc += 2;
+ if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
+ JS_ThrowReferenceErrorUninitialized2(caller_ctx, b, idx, FALSE);
+ goto exception;
+ }
+ sp[0] = JS_DupValue(ctx, var_buf[idx]);
+ sp++;
+ }
+ BREAK;
CASE(OP_put_loc_check):
{
int idx;
@@ -17372,6 +17363,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
op1 = sp[-1];
pc += 4;
+ /* quick and dirty test for JS_TAG_INT, JS_TAG_BOOL, JS_TAG_NULL and JS_TAG_UNDEFINED */
if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
res = JS_VALUE_GET_INT(op1);
} else {
@@ -17518,26 +17510,21 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
}
sp--;
BREAK;
- CASE(OP_iterator_close_return):
+ CASE(OP_nip_catch):
{
JSValue ret_val;
- /* iter_obj next catch_offset ... ret_val ->
- ret_eval iter_obj next catch_offset */
+ /* catch_offset ... ret_val -> ret_eval */
ret_val = *--sp;
while (sp > stack_buf &&
JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_CATCH_OFFSET) {
JS_FreeValue(ctx, *--sp);
}
- if (unlikely(sp < stack_buf + 3)) {
- JS_ThrowInternalError(ctx, "iterator_close_return");
+ if (unlikely(sp == stack_buf)) {
+ JS_ThrowInternalError(ctx, "nip_catch");
JS_FreeValue(ctx, ret_val);
goto exception;
}
- sp[0] = sp[-1];
- sp[-1] = sp[-2];
- sp[-2] = sp[-3];
- sp[-3] = ret_val;
- sp++;
+ sp[-1] = ret_val;
}
BREAK;
@@ -17546,7 +17533,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
JSValue ret;
ret = JS_Call(ctx, sp[-3], sp[-4],
- 1, (sp - 1));
+ 1, (JSValueConst *)(sp - 1));
if (JS_IsException(ret))
goto exception;
JS_FreeValue(ctx, sp[-1]);
@@ -17574,7 +17561,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
0, NULL);
} else {
ret = JS_CallFree(ctx, method, sp[-4],
- 1, (sp - 1));
+ 1, (JSValueConst *)(sp - 1));
}
if (JS_IsException(ret))
goto exception;
@@ -17638,7 +17625,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
atom = get_u32(pc);
pc += 4;
- ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1],
+ ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1], sp[-2],
JS_PROP_THROW_STRICT);
JS_FreeValue(ctx, sp[-2]);
sp -= 2;
@@ -17937,8 +17924,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
atom = JS_ValueToAtom(ctx, sp[-2]);
if (unlikely(atom == JS_ATOM_NULL))
goto exception;
- ret = JS_SetPropertyGeneric(ctx, sp[-3], atom, sp[-1], sp[-4],
- JS_PROP_THROW_STRICT);
+ ret = JS_SetPropertyInternal(ctx, sp[-3], atom, sp[-1], sp[-4],
+ JS_PROP_THROW_STRICT);
JS_FreeAtom(ctx, atom);
JS_FreeValue(ctx, sp[-4]);
JS_FreeValue(ctx, sp[-3]);
@@ -17997,9 +17984,14 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
sp[-2] = JS_NewInt32(ctx, r);
sp--;
} else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
- sp[-2] = JS_NewFloat64Impl(ctx, JS_VALUE_GET_FLOAT64(op1) +
+ sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) +
JS_VALUE_GET_FLOAT64(op2));
sp--;
+ } else if (JS_IsString(op1) && JS_IsString(op2)) {
+ sp[-2] = JS_ConcatString(ctx, op1, op2);
+ sp--;
+ if (JS_IsException(sp[-1]))
+ goto exception;
} else {
add_slow:
if (js_add_slow(ctx, sp))
@@ -18010,38 +18002,45 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
BREAK;
CASE(OP_add_loc):
{
+ JSValue op2;
JSValue *pv;
int idx;
idx = *pc;
pc += 1;
+ op2 = sp[-1];
pv = &var_buf[idx];
- if (likely(JS_VALUE_IS_BOTH_INT(*pv, sp[-1]))) {
+ if (likely(JS_VALUE_IS_BOTH_INT(*pv, op2))) {
int64_t r;
- r = (int64_t)JS_VALUE_GET_INT(*pv) +
- JS_VALUE_GET_INT(sp[-1]);
+ r = (int64_t)JS_VALUE_GET_INT(*pv) + JS_VALUE_GET_INT(op2);
if (unlikely((int)r != r))
goto add_loc_slow;
*pv = JS_NewInt32(ctx, r);
sp--;
+ } else if (JS_VALUE_IS_BOTH_FLOAT(*pv, op2)) {
+ *pv = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(*pv) +
+ JS_VALUE_GET_FLOAT64(op2));
+ sp--;
} else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING) {
- JSValue op1;
- op1 = sp[-1];
sp--;
- op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
- if (JS_IsException(op1))
+ op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
+ if (JS_IsException(op2))
goto exception;
- op1 = JS_ConcatString(ctx, JS_DupValue(ctx, *pv), op1);
- if (JS_IsException(op1))
- goto exception;
- set_value(ctx, pv, op1);
+ if (JS_ConcatStringInPlace(ctx, JS_VALUE_GET_STRING(*pv), op2)) {
+ JS_FreeValue(ctx, op2);
+ } else {
+ op2 = JS_ConcatString(ctx, JS_DupValue(ctx, *pv), op2);
+ if (JS_IsException(op2))
+ goto exception;
+ set_value(ctx, pv, op2);
+ }
} else {
JSValue ops[2];
add_loc_slow:
/* In case of exception, js_add_slow frees ops[0]
and ops[1], so we must duplicate *pv */
ops[0] = JS_DupValue(ctx, *pv);
- ops[1] = sp[-1];
+ ops[1] = op2;
sp--;
if (js_add_slow(ctx, ops + 2))
goto exception;
@@ -18062,8 +18061,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
sp[-2] = JS_NewInt32(ctx, r);
sp--;
} else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
- sp[-2] = JS_NewFloat64Impl(ctx, JS_VALUE_GET_FLOAT64(op1) -
- JS_VALUE_GET_FLOAT64(op2));
+ sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) -
+ JS_VALUE_GET_FLOAT64(op2));
sp--;
} else {
goto binary_arith_slow;
@@ -18105,7 +18104,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
#endif
d = JS_VALUE_GET_FLOAT64(op1) * JS_VALUE_GET_FLOAT64(op2);
mul_fp_res:
- sp[-2] = JS_NewFloat64Impl(ctx, d);
+ sp[-2] = __JS_NewFloat64(ctx, d);
sp--;
} else {
goto binary_arith_slow;
@@ -18197,7 +18196,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
} else if (JS_TAG_IS_FLOAT64(tag)) {
d = -JS_VALUE_GET_FLOAT64(op1);
neg_fp_res:
- sp[-1] = JS_NewFloat64Impl(ctx, d);
+ sp[-1] = __JS_NewFloat64(ctx, d);
} else {
if (js_unary_arith_slow(ctx, sp, opcode))
goto exception;
@@ -18487,6 +18486,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
goto exception;
sp--;
BREAK;
+ CASE(OP_private_in):
+ if (js_operator_private_in(ctx, sp))
+ goto exception;
+ sp--;
+ BREAK;
CASE(OP_instanceof):
if (js_operator_instanceof(ctx, sp))
goto exception;
@@ -18617,7 +18621,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
break;
case OP_with_put_var:
/* XXX: check if strict mode */
- ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2],
+ ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], obj,
JS_PROP_THROW_STRICT);
JS_FreeValue(ctx, sp[-1]);
sp -= 2;
@@ -18673,9 +18677,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD_STAR);
goto done_generator;
CASE(OP_return_async):
- CASE(OP_initial_yield):
ret_val = JS_UNDEFINED;
goto done_generator;
+ CASE(OP_initial_yield):
+ ret_val = JS_NewInt32(ctx, FUNC_RET_INITIAL_YIELD);
+ goto done_generator;
CASE(OP_nop):
BREAK;
@@ -18794,14 +18800,14 @@ JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj,
int argc, JSValueConst *argv)
{
return JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,
- argc, argv, JS_CALL_FLAG_COPY_ARGV);
+ argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV);
}
static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj,
int argc, JSValueConst *argv)
{
JSValue res = JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,
- argc, argv, JS_CALL_FLAG_COPY_ARGV);
+ argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV);
JS_FreeValue(ctx, func_obj);
return res;
}
@@ -18906,7 +18912,7 @@ static JSValue JS_CallConstructorInternal(JSContext *ctx,
return JS_ThrowTypeError(ctx, "not a function");
}
return call_func(ctx, func_obj, new_target, argc,
- argv, flags);
+ (JSValueConst *)argv, flags);
}
b = p->u.func.function_bytecode;
@@ -18935,7 +18941,7 @@ JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj,
int argc, JSValueConst *argv)
{
return JS_CallConstructorInternal(ctx, func_obj, new_target,
- argc, argv,
+ argc, (JSValue *)argv,
JS_CALL_FLAG_COPY_ARGV);
}
@@ -18943,7 +18949,7 @@ JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj,
int argc, JSValueConst *argv)
{
return JS_CallConstructorInternal(ctx, func_obj, func_obj,
- argc, argv,
+ argc, (JSValue *)argv,
JS_CALL_FLAG_COPY_ARGV);
}
@@ -18966,26 +18972,35 @@ static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
}
/* JSAsyncFunctionState (used by generator and async functions) */
-static warn_unused int async_func_init(JSContext *ctx, JSAsyncFunctionState *s,
- JSValueConst func_obj, JSValueConst this_obj,
- int argc, JSValueConst *argv)
+static JSAsyncFunctionState *async_func_init(JSContext *ctx,
+ JSValueConst func_obj, JSValueConst this_obj,
+ int argc, JSValueConst *argv)
{
+ JSAsyncFunctionState *s;
JSObject *p;
JSFunctionBytecode *b;
JSStackFrame *sf;
int local_count, i, arg_buf_len, n;
+ s = js_mallocz(ctx, sizeof(*s));
+ if (!s)
+ return NULL;
+ s->header.ref_count = 1;
+ add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION);
+
sf = &s->frame;
init_list_head(&sf->var_ref_list);
p = JS_VALUE_GET_OBJ(func_obj);
b = p->u.func.function_bytecode;
- sf->js_mode = b->js_mode;
+ sf->js_mode = b->js_mode | JS_MODE_ASYNC;
sf->cur_pc = b->byte_code_buf;
arg_buf_len = max_int(b->arg_count, argc);
local_count = arg_buf_len + b->var_count + b->stack_size;
sf->arg_buf = js_malloc(ctx, sizeof(JSValue) * max_int(local_count, 1));
- if (!sf->arg_buf)
- return -1;
+ if (!sf->arg_buf) {
+ js_free(ctx, s);
+ return NULL;
+ }
sf->cur_func = JS_DupValue(ctx, func_obj);
s->this_val = JS_DupValue(ctx, this_obj);
s->argc = argc;
@@ -18997,38 +19012,17 @@ static warn_unused int async_func_init(JSContext *ctx, JSAsyncFunctionState *s,
n = arg_buf_len + b->var_count;
for(i = argc; i < n; i++)
sf->arg_buf[i] = JS_UNDEFINED;
- return 0;
-}
-
-static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s,
- JS_MarkFunc *mark_func)
-{
- JSStackFrame *sf;
- JSValue *sp;
-
- sf = &s->frame;
- JS_MarkValue(rt, sf->cur_func, mark_func);
- JS_MarkValue(rt, s->this_val, mark_func);
- if (sf->cur_sp) {
- /* if the function is running, cur_sp is not known so we
- cannot mark the stack. Marking the variables is not needed
- because a running function cannot be part of a removable
- cycle */
- for(sp = sf->arg_buf; sp < sf->cur_sp; sp++)
- JS_MarkValue(rt, *sp, mark_func);
- }
+ s->resolving_funcs[0] = JS_UNDEFINED;
+ s->resolving_funcs[1] = JS_UNDEFINED;
+ s->is_completed = FALSE;
+ return s;
}
-static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
+static void async_func_free_frame(JSRuntime *rt, JSAsyncFunctionState *s)
{
- JSStackFrame *sf;
+ JSStackFrame *sf = &s->frame;
JSValue *sp;
- sf = &s->frame;
-
- /* close the closure variables. */
- close_var_refs(rt, sf);
-
if (sf->arg_buf) {
/* cannot free the function if it is running */
assert(sf->cur_sp != NULL);
@@ -19036,6 +19030,7 @@ static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
JS_FreeValueRT(rt, *sp);
}
js_free_rt(rt, sf->arg_buf);
+ sf->arg_buf = NULL;
}
JS_FreeValueRT(rt, sf->cur_func);
JS_FreeValueRT(rt, s->this_val);
@@ -19043,17 +19038,66 @@ static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s)
{
- JSValue func_obj;
+ JSRuntime *rt = ctx->rt;
+ JSStackFrame *sf = &s->frame;
+ JSValue func_obj, ret;
- if (js_check_stack_overflow(ctx->rt, 0))
- return JS_ThrowStackOverflow(ctx);
+ assert(!s->is_completed);
+ if (js_check_stack_overflow(ctx->rt, 0)) {
+ ret = JS_ThrowStackOverflow(ctx);
+ } else {
+ /* the tag does not matter provided it is not an object */
+ func_obj = JS_MKPTR(JS_TAG_INT, s);
+ ret = JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED,
+ s->argc, sf->arg_buf, JS_CALL_FLAG_GENERATOR);
+ }
+ if (JS_IsException(ret) || JS_IsUndefined(ret)) {
+ if (JS_IsUndefined(ret)) {
+ ret = sf->cur_sp[-1];
+ sf->cur_sp[-1] = JS_UNDEFINED;
+ }
+ /* end of execution */
+ s->is_completed = TRUE;
- /* the tag does not matter provided it is not an object */
- func_obj = JS_MKPTR(JS_TAG_INT, s);
- return JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED,
- s->argc, s->frame.arg_buf, JS_CALL_FLAG_GENERATOR);
+ /* close the closure variables. */
+ close_var_refs(rt, sf);
+
+ async_func_free_frame(rt, s);
+ }
+ return ret;
}
+static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
+{
+ /* cannot close the closure variables here because it would
+ potentially modify the object graph */
+ if (!s->is_completed) {
+ async_func_free_frame(rt, s);
+ }
+
+ JS_FreeValueRT(rt, s->resolving_funcs[0]);
+ JS_FreeValueRT(rt, s->resolving_funcs[1]);
+
+ remove_gc_object(&s->header);
+ if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && s->header.ref_count != 0) {
+ list_add_tail(&s->header.link, &rt->gc_zero_ref_count_list);
+ } else {
+ js_free_rt(rt, s);
+ }
+}
+
+static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
+{
+ if (--s->header.ref_count == 0) {
+ if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
+ list_del(&s->header.link);
+ list_add(&s->header.link, &rt->gc_zero_ref_count_list);
+ if (rt->gc_phase == JS_GC_PHASE_NONE) {
+ free_zero_refcount(rt);
+ }
+ }
+ }
+}
/* Generators */
@@ -19067,14 +19111,17 @@ typedef enum JSGeneratorStateEnum {
typedef struct JSGeneratorData {
JSGeneratorStateEnum state;
- JSAsyncFunctionState func_state;
+ JSAsyncFunctionState *func_state;
} JSGeneratorData;
static void free_generator_stack_rt(JSRuntime *rt, JSGeneratorData *s)
{
if (s->state == JS_GENERATOR_STATE_COMPLETED)
return;
- async_func_free(rt, &s->func_state);
+ if (s->func_state) {
+ async_func_free(rt, s->func_state);
+ s->func_state = NULL;
+ }
s->state = JS_GENERATOR_STATE_COMPLETED;
}
@@ -19099,9 +19146,9 @@ static void js_generator_mark(JSRuntime *rt, JSValueConst val,
JSObject *p = JS_VALUE_GET_OBJ(val);
JSGeneratorData *s = p->u.generator_data;
- if (!s || s->state == JS_GENERATOR_STATE_COMPLETED)
+ if (!s || !s->func_state)
return;
- async_func_mark(rt, &s->func_state, mark_func);
+ mark_func(rt, &s->func_state->header);
}
/* XXX: use enum */
@@ -19120,10 +19167,10 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
*pdone = TRUE;
if (!s)
return JS_ThrowTypeError(ctx, "not a generator");
- sf = &s->func_state.frame;
switch(s->state) {
default:
case JS_GENERATOR_STATE_SUSPENDED_START:
+ sf = &s->func_state->frame;
if (magic == GEN_MAGIC_NEXT) {
goto exec_no_arg;
} else {
@@ -19133,28 +19180,29 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
break;
case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
case JS_GENERATOR_STATE_SUSPENDED_YIELD:
+ sf = &s->func_state->frame;
/* cur_sp[-1] was set to JS_UNDEFINED in the previous call */
ret = JS_DupValue(ctx, argv[0]);
if (magic == GEN_MAGIC_THROW &&
s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) {
JS_Throw(ctx, ret);
- s->func_state.throw_flag = TRUE;
+ s->func_state->throw_flag = TRUE;
} else {
sf->cur_sp[-1] = ret;
sf->cur_sp[0] = JS_NewInt32(ctx, magic);
sf->cur_sp++;
exec_no_arg:
- s->func_state.throw_flag = FALSE;
+ s->func_state->throw_flag = FALSE;
}
s->state = JS_GENERATOR_STATE_EXECUTING;
- func_ret = async_func_resume(ctx, &s->func_state);
+ func_ret = async_func_resume(ctx, s->func_state);
s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD;
- if (JS_IsException(func_ret)) {
- /* finalize the execution in case of exception */
+ if (s->func_state->is_completed) {
+ /* finalize the execution in case of exception or normal return */
free_generator_stack(ctx, s);
return func_ret;
- }
- if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
+ } else {
+ assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT);
/* get the returned yield value at the top of the stack */
ret = sf->cur_sp[-1];
sf->cur_sp[-1] = JS_UNDEFINED;
@@ -19165,12 +19213,6 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
} else {
*pdone = FALSE;
}
- } else {
- /* end of iterator */
- ret = sf->cur_sp[-1];
- sf->cur_sp[-1] = JS_UNDEFINED;
- JS_FreeValue(ctx, func_ret);
- free_generator_stack(ctx, s);
}
break;
case JS_GENERATOR_STATE_COMPLETED:
@@ -19208,13 +19250,14 @@ static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
if (!s)
return JS_EXCEPTION;
s->state = JS_GENERATOR_STATE_SUSPENDED_START;
- if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
+ s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv);
+ if (!s->func_state) {
s->state = JS_GENERATOR_STATE_COMPLETED;
goto fail;
}
/* execute the function up to 'OP_initial_yield' */
- func_ret = async_func_resume(ctx, &s->func_state);
+ func_ret = async_func_resume(ctx, s->func_state);
if (JS_IsException(func_ret))
goto fail;
JS_FreeValue(ctx, func_ret);
@@ -19232,36 +19275,12 @@ static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
/* AsyncFunction */
-static void js_async_function_terminate(JSRuntime *rt, JSAsyncFunctionData *s)
-{
- if (s->is_active) {
- async_func_free(rt, &s->func_state);
- s->is_active = FALSE;
- }
-}
-
-static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s)
-{
- js_async_function_terminate(rt, s);
- JS_FreeValueRT(rt, s->resolving_funcs[0]);
- JS_FreeValueRT(rt, s->resolving_funcs[1]);
- remove_gc_object(&s->header);
- js_free_rt(rt, s);
-}
-
-static void js_async_function_free(JSRuntime *rt, JSAsyncFunctionData *s)
-{
- if (--s->header.ref_count == 0) {
- js_async_function_free0(rt, s);
- }
-}
-
static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val)
{
JSObject *p = JS_VALUE_GET_OBJ(val);
- JSAsyncFunctionData *s = p->u.async_function_data;
+ JSAsyncFunctionState *s = p->u.async_function_data;
if (s) {
- js_async_function_free(rt, s);
+ async_func_free(rt, s);
}
}
@@ -19269,14 +19288,14 @@ static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
JS_MarkFunc *mark_func)
{
JSObject *p = JS_VALUE_GET_OBJ(val);
- JSAsyncFunctionData *s = p->u.async_function_data;
+ JSAsyncFunctionState *s = p->u.async_function_data;
if (s) {
mark_func(rt, &s->header);
}
}
static int js_async_function_resolve_create(JSContext *ctx,
- JSAsyncFunctionData *s,
+ JSAsyncFunctionState *s,
JSValue *resolving_funcs)
{
int i;
@@ -19298,60 +19317,58 @@ static int js_async_function_resolve_create(JSContext *ctx,
return 0;
}
-static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionData *s)
+static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionState *s)
{
JSValue func_ret, ret2;
- func_ret = async_func_resume(ctx, &s->func_state);
- if (JS_IsException(func_ret)) {
- JSValue error;
- fail:
- error = JS_GetException(ctx);
- ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED,
- 1, &error);
- JS_FreeValue(ctx, error);
- js_async_function_terminate(ctx->rt, s);
- JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
- } else {
- JSValue value;
- value = s->func_state.frame.cur_sp[-1];
- s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
- if (JS_IsUndefined(func_ret)) {
- /* function returned */
- ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED,
- 1, &value);
+ func_ret = async_func_resume(ctx, s);
+ if (s->is_completed) {
+ if (JS_IsException(func_ret)) {
+ JSValue error;
+ fail:
+ error = JS_GetException(ctx);
+ ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED,
+ 1, (JSValueConst *)&error);
+ JS_FreeValue(ctx, error);
JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
- JS_FreeValue(ctx, value);
- js_async_function_terminate(ctx->rt, s);
} else {
- JSValue promise, resolving_funcs[2], resolving_funcs1[2];
- int i, res;
+ /* normal return */
+ ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED,
+ 1, (JSValueConst *)&func_ret);
+ JS_FreeValue(ctx, func_ret);
+ JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
+ }
+ } else {
+ JSValue value, promise, resolving_funcs[2], resolving_funcs1[2];
+ int i, res;
- /* await */
- JS_FreeValue(ctx, func_ret); /* not used */
- promise = js_promise_resolve(ctx, ctx->promise_ctor,
- 1, &value, 0);
- JS_FreeValue(ctx, value);
- if (JS_IsException(promise))
- goto fail;
- if (js_async_function_resolve_create(ctx, s, resolving_funcs)) {
- JS_FreeValue(ctx, promise);
- goto fail;
- }
+ value = s->frame.cur_sp[-1];
+ s->frame.cur_sp[-1] = JS_UNDEFINED;
- /* Note: no need to create 'thrownawayCapability' as in
- the spec */
- for(i = 0; i < 2; i++)
- resolving_funcs1[i] = JS_UNDEFINED;
- res = perform_promise_then(ctx, promise,
- (JSValueConst *)resolving_funcs,
- (JSValueConst *)resolving_funcs1);
+ /* await */
+ JS_FreeValue(ctx, func_ret); /* not used */
+ promise = js_promise_resolve(ctx, ctx->promise_ctor,
+ 1, (JSValueConst *)&value, 0);
+ JS_FreeValue(ctx, value);
+ if (JS_IsException(promise))
+ goto fail;
+ if (js_async_function_resolve_create(ctx, s, resolving_funcs)) {
JS_FreeValue(ctx, promise);
- for(i = 0; i < 2; i++)
- JS_FreeValue(ctx, resolving_funcs[i]);
- if (res)
- goto fail;
+ goto fail;
}
+
+ /* Note: no need to create 'thrownawayCapability' as in
+ the spec */
+ for(i = 0; i < 2; i++)
+ resolving_funcs1[i] = JS_UNDEFINED;
+ res = perform_promise_then(ctx, promise,
+ (JSValueConst *)resolving_funcs,
+ (JSValueConst *)resolving_funcs1);
+ JS_FreeValue(ctx, promise);
+ for(i = 0; i < 2; i++)
+ JS_FreeValue(ctx, resolving_funcs[i]);
+ if (res)
+ goto fail;
}
}
@@ -19362,7 +19379,7 @@ static JSValue js_async_function_resolve_call(JSContext *ctx,
int flags)
{
JSObject *p = JS_VALUE_GET_OBJ(func_obj);
- JSAsyncFunctionData *s = p->u.async_function_data;
+ JSAsyncFunctionState *s = p->u.async_function_data;
BOOL is_reject = p->class_id - JS_CLASS_ASYNC_FUNCTION_RESOLVE;
JSValueConst arg;
@@ -19370,12 +19387,12 @@ static JSValue js_async_function_resolve_call(JSContext *ctx,
arg = argv[0];
else
arg = JS_UNDEFINED;
- s->func_state.throw_flag = is_reject;
+ s->throw_flag = is_reject;
if (is_reject) {
JS_Throw(ctx, JS_DupValue(ctx, arg));
} else {
/* return value of await */
- s->func_state.frame.cur_sp[-1] = JS_DupValue(ctx, arg);
+ s->frame.cur_sp[-1] = JS_DupValue(ctx, arg);
}
js_async_function_resume(ctx, s);
return JS_UNDEFINED;
@@ -19386,32 +19403,21 @@ static JSValue js_async_function_call(JSContext *ctx, JSValueConst func_obj,
int argc, JSValueConst *argv, int flags)
{
JSValue promise;
- JSAsyncFunctionData *s;
+ JSAsyncFunctionState *s;
- s = js_mallocz(ctx, sizeof(*s));
+ s = async_func_init(ctx, func_obj, this_obj, argc, argv);
if (!s)
return JS_EXCEPTION;
- s->header.ref_count = 1;
- add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION);
- s->is_active = FALSE;
- s->resolving_funcs[0] = JS_UNDEFINED;
- s->resolving_funcs[1] = JS_UNDEFINED;
promise = JS_NewPromiseCapability(ctx, s->resolving_funcs);
- if (JS_IsException(promise))
- goto fail;
-
- if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
- fail:
- JS_FreeValue(ctx, promise);
- js_async_function_free(ctx->rt, s);
+ if (JS_IsException(promise)) {
+ async_func_free(ctx->rt, s);
return JS_EXCEPTION;
}
- s->is_active = TRUE;
js_async_function_resume(ctx, s);
- js_async_function_free(ctx->rt, s);
+ async_func_free(ctx->rt, s);
return promise;
}
@@ -19440,7 +19446,8 @@ typedef struct JSAsyncGeneratorRequest {
typedef struct JSAsyncGeneratorData {
JSObject *generator; /* back pointer to the object (const) */
JSAsyncGeneratorStateEnum state;
- JSAsyncFunctionState func_state;
+ /* func_state is NULL is state AWAITING_RETURN and COMPLETED */
+ JSAsyncFunctionState *func_state;
struct list_head queue; /* list of JSAsyncGeneratorRequest.link */
} JSAsyncGeneratorData;
@@ -19458,10 +19465,8 @@ static void js_async_generator_free(JSRuntime *rt,
JS_FreeValueRT(rt, req->resolving_funcs[1]);
js_free_rt(rt, req);
}
- if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED &&
- s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) {
- async_func_free(rt, &s->func_state);
- }
+ if (s->func_state)
+ async_func_free(rt, s->func_state);
js_free_rt(rt, s);
}
@@ -19488,9 +19493,8 @@ static void js_async_generator_mark(JSRuntime *rt, JSValueConst val,
JS_MarkValue(rt, req->resolving_funcs[0], mark_func);
JS_MarkValue(rt, req->resolving_funcs[1], mark_func);
}
- if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED &&
- s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) {
- async_func_mark(rt, &s->func_state, mark_func);
+ if (s->func_state) {
+ mark_func(rt, &s->func_state->header);
}
}
}
@@ -19600,7 +19604,8 @@ static void js_async_generator_complete(JSContext *ctx,
{
if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED) {
s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
- async_func_free(ctx->rt, &s->func_state);
+ async_func_free(ctx->rt, s->func_state);
+ s->func_state = NULL;
}
}
@@ -19611,10 +19616,19 @@ static int js_async_generator_completed_return(JSContext *ctx,
JSValue promise, resolving_funcs[2], resolving_funcs1[2];
int res;
- promise = js_promise_resolve(ctx, ctx->promise_ctor,
- 1, &value, 0);
- if (JS_IsException(promise))
- return -1;
+ // Can fail looking up JS_ATOM_constructor when is_reject==0.
+ promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, &value,
+ /*is_reject*/0);
+ // A poisoned .constructor property is observable and the resulting
+ // exception should be delivered to the catch handler.
+ if (JS_IsException(promise)) {
+ JSValue err = JS_GetException(ctx);
+ promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, (JSValueConst *)&err,
+ /*is_reject*/1);
+ JS_FreeValue(ctx, err);
+ if (JS_IsException(promise))
+ return -1;
+ }
if (js_async_generator_resolve_function_create(ctx,
JS_MKPTR(JS_TAG_OBJECT, s->generator),
resolving_funcs1,
@@ -19662,7 +19676,6 @@ static void js_async_generator_resume_next(JSContext *ctx,
} else if (next->completion_type == GEN_MAGIC_RETURN) {
s->state = JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN;
js_async_generator_completed_return(ctx, s, next->result);
- goto done;
} else {
js_async_generator_reject(ctx, s, next->result);
}
@@ -19673,30 +19686,38 @@ static void js_async_generator_resume_next(JSContext *ctx,
if (next->completion_type == GEN_MAGIC_THROW &&
s->state == JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD) {
JS_Throw(ctx, value);
- s->func_state.throw_flag = TRUE;
+ s->func_state->throw_flag = TRUE;
} else {
/* 'yield' returns a value. 'yield *' also returns a value
in case the 'throw' method is called */
- s->func_state.frame.cur_sp[-1] = value;
- s->func_state.frame.cur_sp[0] =
+ s->func_state->frame.cur_sp[-1] = value;
+ s->func_state->frame.cur_sp[0] =
JS_NewInt32(ctx, next->completion_type);
- s->func_state.frame.cur_sp++;
+ s->func_state->frame.cur_sp++;
exec_no_arg:
- s->func_state.throw_flag = FALSE;
+ s->func_state->throw_flag = FALSE;
}
s->state = JS_ASYNC_GENERATOR_STATE_EXECUTING;
resume_exec:
- func_ret = async_func_resume(ctx, &s->func_state);
- if (JS_IsException(func_ret)) {
- value = JS_GetException(ctx);
- js_async_generator_complete(ctx, s);
- js_async_generator_reject(ctx, s, value);
- JS_FreeValue(ctx, value);
- } else if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
- int func_ret_code;
- value = s->func_state.frame.cur_sp[-1];
- s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
+ func_ret = async_func_resume(ctx, s->func_state);
+ if (s->func_state->is_completed) {
+ if (JS_IsException(func_ret)) {
+ value = JS_GetException(ctx);
+ js_async_generator_complete(ctx, s);
+ js_async_generator_reject(ctx, s, value);
+ JS_FreeValue(ctx, value);
+ } else {
+ /* end of function */
+ js_async_generator_complete(ctx, s);
+ js_async_generator_resolve(ctx, s, func_ret, TRUE);
+ JS_FreeValue(ctx, func_ret);
+ }
+ } else {
+ int func_ret_code, ret;
+ assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT);
func_ret_code = JS_VALUE_GET_INT(func_ret);
+ value = s->func_state->frame.cur_sp[-1];
+ s->func_state->frame.cur_sp[-1] = JS_UNDEFINED;
switch(func_ret_code) {
case FUNC_RET_YIELD:
case FUNC_RET_YIELD_STAR:
@@ -19708,20 +19729,17 @@ static void js_async_generator_resume_next(JSContext *ctx,
JS_FreeValue(ctx, value);
break;
case FUNC_RET_AWAIT:
- js_async_generator_await(ctx, s, value);
+ ret = js_async_generator_await(ctx, s, value);
JS_FreeValue(ctx, value);
+ if (ret < 0) {
+ /* exception: throw it */
+ s->func_state->throw_flag = TRUE;
+ goto resume_exec;
+ }
goto done;
default:
abort();
}
- } else {
- assert(JS_IsUndefined(func_ret));
- /* end of function */
- value = s->func_state.frame.cur_sp[-1];
- s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
- js_async_generator_complete(ctx, s);
- js_async_generator_resolve(ctx, s, value, TRUE);
- JS_FreeValue(ctx, value);
}
break;
default:
@@ -19755,12 +19773,12 @@ static JSValue js_async_generator_resolve_function(JSContext *ctx,
} else {
/* restart function execution after await() */
assert(s->state == JS_ASYNC_GENERATOR_STATE_EXECUTING);
- s->func_state.throw_flag = is_reject;
+ s->func_state->throw_flag = is_reject;
if (is_reject) {
JS_Throw(ctx, JS_DupValue(ctx, arg));
} else {
/* return value of await */
- s->func_state.frame.cur_sp[-1] = JS_DupValue(ctx, arg);
+ s->func_state->frame.cur_sp[-1] = JS_DupValue(ctx, arg);
}
js_async_generator_resume_next(ctx, s);
}
@@ -19784,7 +19802,7 @@ static JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val,
JS_ThrowTypeError(ctx, "not an AsyncGenerator object");
err = JS_GetException(ctx);
res2 = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
- 1, &err);
+ 1, (JSValueConst *)&err);
JS_FreeValue(ctx, err);
JS_FreeValue(ctx, res2);
JS_FreeValue(ctx, resolving_funcs[0]);
@@ -19824,14 +19842,12 @@ static JSValue js_async_generator_function_call(JSContext *ctx, JSValueConst fun
return JS_EXCEPTION;
s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_START;
init_list_head(&s->queue);
- if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
- s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
+ s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv);
+ if (!s->func_state)
goto fail;
- }
-
/* execute the function up to 'OP_initial_yield' (no yield nor
await are possible) */
- func_ret = async_func_resume(ctx, &s->func_state);
+ func_ret = async_func_resume(ctx, s->func_state);
if (JS_IsException(func_ret))
goto fail;
JS_FreeValue(ctx, func_ret);
@@ -20017,6 +20033,7 @@ typedef enum JSParseFunctionEnum {
JS_PARSE_FUNC_GETTER,
JS_PARSE_FUNC_SETTER,
JS_PARSE_FUNC_METHOD,
+ JS_PARSE_FUNC_CLASS_STATIC_INIT,
JS_PARSE_FUNC_CLASS_CONSTRUCTOR,
JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR,
} JSParseFunctionEnum;
@@ -20136,6 +20153,7 @@ typedef struct JSFunctionDef {
int source_len;
JSModuleDef *module; /* != NULL when parsing a module */
+ BOOL has_await; /* TRUE if await is used (used in module eval) */
} JSFunctionDef;
typedef struct JSToken {
@@ -20219,16 +20237,14 @@ static const JSOpCode opcode_info[OP_COUNT + (OP_TEMP_END - OP_TEMP_START)] = {
#define short_opcode_info(op) opcode_info[op]
#endif
-static warn_unused int next_token(JSParseState *s);
+static __exception int next_token(JSParseState *s);
static void free_token(JSParseState *s, JSToken *token)
{
switch(token->val) {
-#ifdef CONFIG_BIGNUM
case TOK_NUMBER:
JS_FreeValue(s->ctx, token->u.num.val);
break;
-#endif
case TOK_STRING:
case TOK_TEMPLATE:
JS_FreeValue(s->ctx, token->u.str.str);
@@ -20250,7 +20266,7 @@ static void free_token(JSParseState *s, JSToken *token)
}
}
-static void maybe_unused dump_token(JSParseState *s,
+static void __maybe_unused dump_token(JSParseState *s,
const JSToken *token)
{
switch(token->val) {
@@ -20357,7 +20373,7 @@ static int js_parse_error_reserved_identifier(JSParseState *s)
s->token.u.ident.atom));
}
-static warn_unused int js_parse_template_part(JSParseState *s, const uint8_t *p)
+static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p)
{
uint32_t c;
StringBuffer b_s, *b = &b_s;
@@ -20418,7 +20434,7 @@ static warn_unused int js_parse_template_part(JSParseState *s, const uint8_t *p)
return -1;
}
-static warn_unused int js_parse_string(JSParseState *s, int sep,
+static __exception int js_parse_string(JSParseState *s, int sep,
BOOL do_throw, const uint8_t *p,
JSToken *token, const uint8_t **pp)
{
@@ -20563,7 +20579,7 @@ static inline BOOL token_is_pseudo_keyword(JSParseState *s, JSAtom atom) {
!s->token.u.ident.has_escape;
}
-static warn_unused int js_parse_regexp(JSParseState *s)
+static __exception int js_parse_regexp(JSParseState *s)
{
const uint8_t *p;
BOOL in_class;
@@ -20661,7 +20677,7 @@ static warn_unused int js_parse_regexp(JSParseState *s)
return -1;
}
-static warn_unused int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize,
+static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize,
const char *static_buf)
{
char *buf, *new_buf;
@@ -20688,6 +20704,48 @@ static warn_unused int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize,
return 0;
}
+/* convert a TOK_IDENT to a keyword when needed */
+static void update_token_ident(JSParseState *s)
+{
+ if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD ||
+ (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD &&
+ (s->cur_func->js_mode & JS_MODE_STRICT)) ||
+ (s->token.u.ident.atom == JS_ATOM_yield &&
+ ((s->cur_func->func_kind & JS_FUNC_GENERATOR) ||
+ (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
+ !s->cur_func->in_function_body && s->cur_func->parent &&
+ (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) ||
+ (s->token.u.ident.atom == JS_ATOM_await &&
+ (s->is_module ||
+ (s->cur_func->func_kind & JS_FUNC_ASYNC) ||
+ s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT ||
+ (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
+ !s->cur_func->in_function_body && s->cur_func->parent &&
+ ((s->cur_func->parent->func_kind & JS_FUNC_ASYNC) ||
+ s->cur_func->parent->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))))) {
+ if (s->token.u.ident.has_escape) {
+ s->token.u.ident.is_reserved = TRUE;
+ s->token.val = TOK_IDENT;
+ } else {
+ /* The keywords atoms are pre allocated */
+ s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD;
+ }
+ }
+}
+
+/* if the current token is an identifier or keyword, reparse it
+ according to the current function type */
+static void reparse_ident_token(JSParseState *s)
+{
+ if (s->token.val == TOK_IDENT ||
+ (s->token.val >= TOK_FIRST_KEYWORD &&
+ s->token.val <= TOK_LAST_KEYWORD)) {
+ s->token.val = TOK_IDENT;
+ s->token.u.ident.is_reserved = FALSE;
+ update_token_ident(s);
+ }
+}
+
/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
static JSAtom parse_ident(JSParseState *s, const uint8_t **pp,
BOOL *pident_has_escape, int c, BOOL is_private)
@@ -20737,7 +20795,7 @@ static JSAtom parse_ident(JSParseState *s, const uint8_t **pp,
}
-static warn_unused int next_token(JSParseState *s)
+static __exception int next_token(JSParseState *s)
{
const uint8_t *p;
int c;
@@ -20894,30 +20952,8 @@ static warn_unused int next_token(JSParseState *s)
s->token.u.ident.atom = atom;
s->token.u.ident.has_escape = ident_has_escape;
s->token.u.ident.is_reserved = FALSE;
- if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD ||
- (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD &&
- (s->cur_func->js_mode & JS_MODE_STRICT)) ||
- (s->token.u.ident.atom == JS_ATOM_yield &&
- ((s->cur_func->func_kind & JS_FUNC_GENERATOR) ||
- (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
- !s->cur_func->in_function_body && s->cur_func->parent &&
- (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) ||
- (s->token.u.ident.atom == JS_ATOM_await &&
- (s->is_module ||
- (((s->cur_func->func_kind & JS_FUNC_ASYNC) ||
- (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
- !s->cur_func->in_function_body && s->cur_func->parent &&
- (s->cur_func->parent->func_kind & JS_FUNC_ASYNC))))))) {
- if (ident_has_escape) {
- s->token.u.ident.is_reserved = TRUE;
- s->token.val = TOK_IDENT;
- } else {
- /* The keywords atoms are pre allocated */
- s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD;
- }
- } else {
- s->token.val = TOK_IDENT;
- }
+ s->token.val = TOK_IDENT;
+ update_token_ident(s);
break;
case '#':
/* private name */
@@ -20974,8 +21010,8 @@ static warn_unused int next_token(JSParseState *s)
int flags, radix;
flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL |
ATOD_ACCEPT_UNDERSCORES;
-#ifdef CONFIG_BIGNUM
flags |= ATOD_ACCEPT_SUFFIX;
+#ifdef CONFIG_BIGNUM
if (s->cur_func->js_mode & JS_MODE_MATH) {
flags |= ATOD_MODE_BIGINT;
if (s->cur_func->js_mode & JS_MODE_MATH)
@@ -21266,8 +21302,7 @@ static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c)
for(;;) {
buf[ident_pos++] = c;
c = *p;
- if (c >= 128 ||
- !((lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1))
+ if (c >= 128 || !lre_is_id_continue_byte(c))
break;
p++;
if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
@@ -21285,7 +21320,7 @@ static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c)
return atom;
}
-static warn_unused int json_next_token(JSParseState *s)
+static __exception int json_next_token(JSParseState *s)
{
const uint8_t *p;
int c;
@@ -21479,9 +21514,29 @@ static warn_unused int json_next_token(JSParseState *s)
return -1;
}
-/* only used for ':' and '=>', 'let' or 'function' look-ahead. *pp is
- only set if TOK_IMPORT is returned */
-/* XXX: handle all unicode cases */
+static int match_identifier(const uint8_t *p, const char *s) {
+ uint32_t c;
+ while (*s) {
+ if ((uint8_t)*s++ != *p++)
+ return 0;
+ }
+ c = *p;
+ if (c >= 128)
+ c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
+ return !lre_js_is_ident_next(c);
+}
+
+/* simple_next_token() is used to check for the next token in simple cases.
+ It is only used for ':' and '=>', 'let' or 'function' look-ahead.
+ (*pp) is only set if TOK_IMPORT is returned for JS_DetectModule()
+ Whitespace and comments are skipped correctly.
+ Then the next token is analyzed, only for specific words.
+ Return values:
+ - '\n' if !no_line_terminator
+ - TOK_ARROW, TOK_IN, TOK_IMPORT, TOK_OF, TOK_EXPORT, TOK_FUNCTION
+ - TOK_IDENT is returned for other identifiers and keywords
+ - otherwise the next character or unicode codepoint is returned.
+ */
static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator)
{
const uint8_t *p;
@@ -21525,33 +21580,42 @@ static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator)
if (*p == '>')
return TOK_ARROW;
break;
+ case 'i':
+ if (match_identifier(p, "n"))
+ return TOK_IN;
+ if (match_identifier(p, "mport")) {
+ *pp = p + 5;
+ return TOK_IMPORT;
+ }
+ return TOK_IDENT;
+ case 'o':
+ if (match_identifier(p, "f"))
+ return TOK_OF;
+ return TOK_IDENT;
+ case 'e':
+ if (match_identifier(p, "xport"))
+ return TOK_EXPORT;
+ return TOK_IDENT;
+ case 'f':
+ if (match_identifier(p, "unction"))
+ return TOK_FUNCTION;
+ return TOK_IDENT;
+ case '\\':
+ if (*p == 'u') {
+ if (lre_js_is_ident_first(lre_parse_escape(&p, TRUE)))
+ return TOK_IDENT;
+ }
+ break;
default:
- if (lre_js_is_ident_first(c)) {
- if (c == 'i') {
- if (p[0] == 'n' && !lre_js_is_ident_next(p[1])) {
- return TOK_IN;
- }
- if (p[0] == 'm' && p[1] == 'p' && p[2] == 'o' &&
- p[3] == 'r' && p[4] == 't' &&
- !lre_js_is_ident_next(p[5])) {
- *pp = p + 5;
- return TOK_IMPORT;
- }
- } else if (c == 'o' && *p == 'f' && !lre_js_is_ident_next(p[1])) {
- return TOK_OF;
- } else if (c == 'e' &&
- p[0] == 'x' && p[1] == 'p' && p[2] == 'o' &&
- p[3] == 'r' && p[4] == 't' &&
- !lre_js_is_ident_next(p[5])) {
- *pp = p + 5;
- return TOK_EXPORT;
- } else if (c == 'f' && p[0] == 'u' && p[1] == 'n' &&
- p[2] == 'c' && p[3] == 't' && p[4] == 'i' &&
- p[5] == 'o' && p[6] == 'n' && !lre_js_is_ident_next(p[7])) {
- return TOK_FUNCTION;
- }
- return TOK_IDENT;
+ if (c >= 128) {
+ c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p);
+ if (no_line_terminator && (c == CP_PS || c == CP_LS))
+ return '\n';
}
+ if (lre_is_space(c))
+ continue;
+ if (lre_js_is_ident_first(c))
+ return TOK_IDENT;
break;
}
return c;
@@ -21564,6 +21628,31 @@ static int peek_token(JSParseState *s, BOOL no_line_terminator)
return simple_next_token(&p, no_line_terminator);
}
+static void skip_shebang(const uint8_t **pp, const uint8_t *buf_end)
+{
+ const uint8_t *p = *pp;
+ int c;
+
+ if (p[0] == '#' && p[1] == '!') {
+ p += 2;
+ while (p < buf_end) {
+ if (*p == '\n' || *p == '\r') {
+ break;
+ } else if (*p >= 0x80) {
+ c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
+ if (c == CP_LS || c == CP_PS) {
+ break;
+ } else if (c == -1) {
+ p++; /* skip invalid UTF-8 */
+ }
+ } else {
+ p++;
+ }
+ }
+ *pp = p;
+ }
+}
+
/* return true if 'input' contains the source of a module
(heuristic). 'input' must be a zero terminated.
@@ -21574,6 +21663,8 @@ BOOL JS_DetectModule(const char *input, size_t input_len)
{
const uint8_t *p = (const uint8_t *)input;
int tok;
+
+ skip_shebang(&p, p + input_len);
switch(simple_next_token(&p, FALSE)) {
case TOK_IMPORT:
tok = simple_next_token(&p, FALSE);
@@ -21686,6 +21777,14 @@ static int new_label(JSParseState *s)
return new_label_fd(s->cur_func, -1);
}
+/* don't update the last opcode and don't emit line number info */
+static void emit_label_raw(JSParseState *s, int label)
+{
+ emit_u8(s, OP_label);
+ emit_u32(s, label);
+ s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size;
+}
+
/* return the label ID offset */
static int emit_label(JSParseState *s, int label)
{
@@ -21725,7 +21824,7 @@ static int cpool_add(JSParseState *s, JSValue val)
return fd->cpool_count - 1;
}
-static warn_unused int emit_push_const(JSParseState *s, JSValueConst val,
+static __exception int emit_push_const(JSParseState *s, JSValueConst val,
BOOL as_atom)
{
int idx;
@@ -21735,7 +21834,7 @@ static warn_unused int emit_push_const(JSParseState *s, JSValueConst val,
/* warning: JS_NewAtomStr frees the string value */
JS_DupValue(s->ctx, val);
atom = JS_NewAtomStr(s->ctx, JS_VALUE_GET_STRING(val));
- if (atom != JS_ATOM_NULL && !JS_AtomIsTaggedInt(atom)) {
+ if (atom != JS_ATOM_NULL && !__JS_AtomIsTaggedInt(atom)) {
emit_op(s, OP_push_atom_value);
emit_u32(s, atom);
return 0;
@@ -22184,7 +22283,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
/* add a private field variable in the current scope */
static int add_private_class_field(JSParseState *s, JSFunctionDef *fd,
- JSAtom name, JSVarKindEnum var_kind)
+ JSAtom name, JSVarKindEnum var_kind, BOOL is_static)
{
JSContext *ctx = s->ctx;
JSVarDef *vd;
@@ -22196,17 +22295,18 @@ static int add_private_class_field(JSParseState *s, JSFunctionDef *fd,
vd = &fd->vars[idx];
vd->is_lexical = 1;
vd->is_const = 1;
+ vd->is_static_private = is_static;
return idx;
}
-static warn_unused int js_parse_expr(JSParseState *s);
-static warn_unused int js_parse_function_decl(JSParseState *s,
+static __exception int js_parse_expr(JSParseState *s);
+static __exception int js_parse_function_decl(JSParseState *s,
JSParseFunctionEnum func_type,
JSFunctionKindEnum func_kind,
JSAtom func_name, const uint8_t *ptr,
int start_line);
static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s);
-static warn_unused int js_parse_function_decl2(JSParseState *s,
+static __exception int js_parse_function_decl2(JSParseState *s,
JSParseFunctionEnum func_type,
JSFunctionKindEnum func_kind,
JSAtom func_name,
@@ -22214,9 +22314,9 @@ static warn_unused int js_parse_function_decl2(JSParseState *s,
int function_line_num,
JSParseExportEnum export_flag,
JSFunctionDef **pfd);
-static warn_unused int js_parse_assign_expr2(JSParseState *s, int parse_flags);
-static warn_unused int js_parse_assign_expr(JSParseState *s);
-static warn_unused int js_parse_unary(JSParseState *s, int parse_flags);
+static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags);
+static __exception int js_parse_assign_expr(JSParseState *s);
+static __exception int js_parse_unary(JSParseState *s, int parse_flags);
static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
JSAtom label_name,
int label_break, int label_cont,
@@ -22243,7 +22343,7 @@ static int seal_template_obj(JSContext *ctx, JSValueConst obj)
return 0;
}
-static warn_unused int js_parse_template(JSParseState *s, int call, int *argc)
+static __exception int js_parse_template(JSParseState *s, int call, int *argc)
{
JSContext *ctx = s->ctx;
JSValue raw_array, template_object;
@@ -22374,7 +22474,7 @@ static BOOL token_is_ident(int tok)
}
/* if the property is an expression, name = JS_ATOM_NULL */
-static int warn_unused js_parse_property_name(JSParseState *s,
+static int __exception js_parse_property_name(JSParseState *s,
JSAtom *pname,
BOOL allow_method, BOOL allow_var,
BOOL allow_private)
@@ -22393,7 +22493,8 @@ static int warn_unused js_parse_property_name(JSParseState *s,
if (next_token(s))
goto fail1;
if (s->token.val == ':' || s->token.val == ',' ||
- s->token.val == '}' || s->token.val == '(') {
+ s->token.val == '}' || s->token.val == '(' ||
+ s->token.val == '=') {
is_non_reserved_ident = TRUE;
goto ident_found;
}
@@ -22409,7 +22510,8 @@ static int warn_unused js_parse_property_name(JSParseState *s,
if (next_token(s))
goto fail1;
if (s->token.val == ':' || s->token.val == ',' ||
- s->token.val == '}' || s->token.val == '(') {
+ s->token.val == '}' || s->token.val == '(' ||
+ s->token.val == '=') {
is_non_reserved_ident = TRUE;
goto ident_found;
}
@@ -22516,7 +22618,7 @@ static int js_parse_get_pos(JSParseState *s, JSParsePos *sp)
return 0;
}
-static warn_unused int js_parse_seek_token(JSParseState *s, const JSParsePos *sp)
+static __exception int js_parse_seek_token(JSParseState *s, const JSParsePos *sp)
{
s->token.line_num = sp->last_line_num;
s->line_num = sp->line_num;
@@ -22722,7 +22824,7 @@ static void set_object_name_computed(JSParseState *s)
}
}
-static warn_unused int js_parse_object_literal(JSParseState *s)
+static __exception int js_parse_object_literal(JSParseState *s)
{
JSAtom name = JS_ATOM_NULL;
const uint8_t *start_ptr;
@@ -22840,22 +22942,20 @@ static warn_unused int js_parse_object_literal(JSParseState *s)
#define PF_IN_ACCEPTED (1 << 0)
/* allow function calls parsing in js_parse_postfix_expr() */
#define PF_POSTFIX_CALL (1 << 1)
-/* allow arrow functions parsing in js_parse_postfix_expr() */
-#define PF_ARROW_FUNC (1 << 2)
/* allow the exponentiation operator in js_parse_unary() */
-#define PF_POW_ALLOWED (1 << 3)
+#define PF_POW_ALLOWED (1 << 2)
/* forbid the exponentiation operator in js_parse_unary() */
-#define PF_POW_FORBIDDEN (1 << 4)
+#define PF_POW_FORBIDDEN (1 << 3)
-static warn_unused int js_parse_postfix_expr(JSParseState *s, int parse_flags);
+static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags);
-static warn_unused int js_parse_left_hand_side_expr(JSParseState *s)
+static __exception int js_parse_left_hand_side_expr(JSParseState *s)
{
return js_parse_postfix_expr(s, PF_POSTFIX_CALL);
}
/* XXX: could generate specific bytecode */
-static warn_unused int js_parse_class_default_ctor(JSParseState *s,
+static __exception int js_parse_class_default_ctor(JSParseState *s,
BOOL has_super,
JSFunctionDef **pfd)
{
@@ -22942,11 +23042,12 @@ static JSAtom get_private_setter_name(JSContext *ctx, JSAtom name)
typedef struct {
JSFunctionDef *fields_init_fd;
int computed_fields_count;
- BOOL has_brand;
+ BOOL need_brand;
int brand_push_pos;
+ BOOL is_static;
} ClassFieldsDef;
-static warn_unused int emit_class_init_start(JSParseState *s,
+static __exception int emit_class_init_start(JSParseState *s,
ClassFieldsDef *cf)
{
int label_add_brand;
@@ -22957,41 +23058,27 @@ static warn_unused int emit_class_init_start(JSParseState *s,
s->cur_func = cf->fields_init_fd;
- /* XXX: would be better to add the code only if needed, maybe in a
- later pass */
- emit_op(s, OP_push_false); /* will be patched later */
- cf->brand_push_pos = cf->fields_init_fd->last_opcode_pos;
- label_add_brand = emit_goto(s, OP_if_false, -1);
+ if (!cf->is_static) {
+ /* add the brand to the newly created instance */
+ /* XXX: would be better to add the code only if needed, maybe in a
+ later pass */
+ emit_op(s, OP_push_false); /* will be patched later */
+ cf->brand_push_pos = cf->fields_init_fd->last_opcode_pos;
+ label_add_brand = emit_goto(s, OP_if_false, -1);
- emit_op(s, OP_scope_get_var);
- emit_atom(s, JS_ATOM_this);
- emit_u16(s, 0);
-
- emit_op(s, OP_scope_get_var);
- emit_atom(s, JS_ATOM_home_object);
- emit_u16(s, 0);
-
- emit_op(s, OP_add_brand);
-
- emit_label(s, label_add_brand);
+ emit_op(s, OP_scope_get_var);
+ emit_atom(s, JS_ATOM_this);
+ emit_u16(s, 0);
- s->cur_func = s->cur_func->parent;
- return 0;
-}
+ emit_op(s, OP_scope_get_var);
+ emit_atom(s, JS_ATOM_home_object);
+ emit_u16(s, 0);
-static warn_unused int add_brand(JSParseState *s, ClassFieldsDef *cf)
-{
- if (!cf->has_brand) {
- /* define the brand field in 'this' of the initializer */
- if (!cf->fields_init_fd) {
- if (emit_class_init_start(s, cf))
- return -1;
- }
- /* patch the start of the function to enable the OP_add_brand code */
- cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true;
+ emit_op(s, OP_add_brand);
- cf->has_brand = TRUE;
+ emit_label(s, label_add_brand);
}
+ s->cur_func = s->cur_func->parent;
return 0;
}
@@ -23011,7 +23098,7 @@ static void emit_class_init_end(JSParseState *s, ClassFieldsDef *cf)
}
-static warn_unused int js_parse_class(JSParseState *s, BOOL is_class_expr,
+static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
JSParseExportEnum export_flag)
{
JSContext *ctx = s->ctx;
@@ -23098,7 +23185,8 @@ static warn_unused int js_parse_class(JSParseState *s, BOOL is_class_expr,
ClassFieldsDef *cf = &class_fields[i];
cf->fields_init_fd = NULL;
cf->computed_fields_count = 0;
- cf->has_brand = FALSE;
+ cf->need_brand = FALSE;
+ cf->is_static = i;
}
ctor_fd = NULL;
@@ -23108,11 +23196,51 @@ static warn_unused int js_parse_class(JSParseState *s, BOOL is_class_expr,
goto fail;
continue;
}
- is_static = (s->token.val == TOK_STATIC);
+ is_static = FALSE;
+ if (s->token.val == TOK_STATIC) {
+ int next = peek_token(s, TRUE);
+ if (!(next == ';' || next == '}' || next == '(' || next == '='))
+ is_static = TRUE;
+ }
prop_type = -1;
if (is_static) {
if (next_token(s))
goto fail;
+ if (s->token.val == '{') {
+ ClassFieldsDef *cf = &class_fields[is_static];
+ JSFunctionDef *init;
+ if (!cf->fields_init_fd) {
+ if (emit_class_init_start(s, cf))
+ goto fail;
+ }
+ s->cur_func = cf->fields_init_fd;
+ /* XXX: could try to avoid creating a new function and
+ reuse 'fields_init_fd' with a specific 'var'
+ scope */
+ // stack is now: <empty>
+ if (js_parse_function_decl2(s, JS_PARSE_FUNC_CLASS_STATIC_INIT,
+ JS_FUNC_NORMAL, JS_ATOM_NULL,
+ s->token.ptr, s->token.line_num,
+ JS_PARSE_EXPORT_NONE, &init) < 0) {
+ goto fail;
+ }
+ // stack is now: fclosure
+ push_scope(s);
+ emit_op(s, OP_scope_get_var);
+ emit_atom(s, JS_ATOM_this);
+ emit_u16(s, 0);
+ // stack is now: fclosure this
+ emit_op(s, OP_swap);
+ // stack is now: this fclosure
+ emit_op(s, OP_call_method);
+ emit_u16(s, 0);
+ // stack is now: returnvalue
+ emit_op(s, OP_drop);
+ // stack is now: <empty>
+ pop_scope(s);
+ s->cur_func = s->cur_func->parent;
+ continue;
+ }
/* allow "static" field name */
if (s->token.val == ';' || s->token.val == '=') {
is_static = FALSE;
@@ -23143,24 +23271,26 @@ static warn_unused int js_parse_class(JSParseState *s, BOOL is_class_expr,
JSFunctionDef *method_fd;
if (is_private) {
- int idx, var_kind;
+ int idx, var_kind, is_static1;
idx = find_private_class_field(ctx, fd, name, fd->scope_level);
if (idx >= 0) {
var_kind = fd->vars[idx].var_kind;
+ is_static1 = fd->vars[idx].is_static_private;
if (var_kind == JS_VAR_PRIVATE_FIELD ||
var_kind == JS_VAR_PRIVATE_METHOD ||
var_kind == JS_VAR_PRIVATE_GETTER_SETTER ||
- var_kind == (JS_VAR_PRIVATE_GETTER + is_set)) {
+ var_kind == (JS_VAR_PRIVATE_GETTER + is_set) ||
+ (var_kind == (JS_VAR_PRIVATE_GETTER + 1 - is_set) &&
+ is_static != is_static1)) {
goto private_field_already_defined;
}
fd->vars[idx].var_kind = JS_VAR_PRIVATE_GETTER_SETTER;
} else {
if (add_private_class_field(s, fd, name,
- JS_VAR_PRIVATE_GETTER + is_set) < 0)
+ JS_VAR_PRIVATE_GETTER + is_set, is_static) < 0)
goto fail;
}
- if (add_brand(s, &class_fields[is_static]) < 0)
- goto fail;
+ class_fields[is_static].need_brand = TRUE;
}
if (js_parse_function_decl2(s, JS_PARSE_FUNC_GETTER + is_set,
@@ -23182,7 +23312,7 @@ static warn_unused int js_parse_class(JSParseState *s, BOOL is_class_expr,
goto fail;
emit_atom(s, setter_name);
ret = add_private_class_field(s, fd, setter_name,
- JS_VAR_PRIVATE_SETTER);
+ JS_VAR_PRIVATE_SETTER, is_static);
JS_FreeAtom(ctx, setter_name);
if (ret < 0)
goto fail;
@@ -23217,7 +23347,7 @@ static warn_unused int js_parse_class(JSParseState *s, BOOL is_class_expr,
goto private_field_already_defined;
}
if (add_private_class_field(s, fd, name,
- JS_VAR_PRIVATE_FIELD) < 0)
+ JS_VAR_PRIVATE_FIELD, is_static) < 0)
goto fail;
emit_op(s, OP_private_symbol);
emit_atom(s, name);
@@ -23307,8 +23437,7 @@ static warn_unused int js_parse_class(JSParseState *s, BOOL is_class_expr,
func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
}
if (is_private) {
- if (add_brand(s, &class_fields[is_static]) < 0)
- goto fail;
+ class_fields[is_static].need_brand = TRUE;
}
if (js_parse_function_decl2(s, func_type, func_kind, JS_ATOM_NULL, start_ptr, s->token.line_num, JS_PARSE_EXPORT_NONE, &method_fd))
goto fail;
@@ -23324,7 +23453,7 @@ static warn_unused int js_parse_class(JSParseState *s, BOOL is_class_expr,
goto fail;
}
if (add_private_class_field(s, fd, name,
- JS_VAR_PRIVATE_METHOD) < 0)
+ JS_VAR_PRIVATE_METHOD, is_static) < 0)
goto fail;
emit_op(s, OP_set_home_object);
emit_op(s, OP_set_name);
@@ -23374,12 +23503,29 @@ static warn_unused int js_parse_class(JSParseState *s, BOOL is_class_expr,
if (next_token(s))
goto fail;
- /* store the function to initialize the fields to that it can be
- referenced by the constructor */
{
ClassFieldsDef *cf = &class_fields[0];
int var_idx;
+ if (cf->need_brand) {
+ /* add a private brand to the prototype */
+ emit_op(s, OP_dup);
+ emit_op(s, OP_null);
+ emit_op(s, OP_swap);
+ emit_op(s, OP_add_brand);
+
+ /* define the brand field in 'this' of the initializer */
+ if (!cf->fields_init_fd) {
+ if (emit_class_init_start(s, cf))
+ goto fail;
+ }
+ /* patch the start of the function to enable the
+ OP_add_brand_instance code */
+ cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true;
+ }
+
+ /* store the function to initialize the fields to that it can be
+ referenced by the constructor */
var_idx = define_var(s, fd, JS_ATOM_class_fields_init,
JS_VAR_DEF_CONST);
if (var_idx < 0)
@@ -23397,14 +23543,11 @@ static warn_unused int js_parse_class(JSParseState *s, BOOL is_class_expr,
/* drop the prototype */
emit_op(s, OP_drop);
- /* initialize the static fields */
- if (class_fields[1].fields_init_fd != NULL) {
- ClassFieldsDef *cf = &class_fields[1];
+ if (class_fields[1].need_brand) {
+ /* add a private brand to the class */
emit_op(s, OP_dup);
- emit_class_init_end(s, cf);
- emit_op(s, OP_call_method);
- emit_u16(s, 0);
- emit_op(s, OP_drop);
+ emit_op(s, OP_dup);
+ emit_op(s, OP_add_brand);
}
if (class_name != JS_ATOM_NULL) {
@@ -23416,6 +23559,17 @@ static warn_unused int js_parse_class(JSParseState *s, BOOL is_class_expr,
emit_atom(s, class_name);
emit_u16(s, fd->scope_level);
}
+
+ /* initialize the static fields */
+ if (class_fields[1].fields_init_fd != NULL) {
+ ClassFieldsDef *cf = &class_fields[1];
+ emit_op(s, OP_dup);
+ emit_class_init_end(s, cf);
+ emit_op(s, OP_call_method);
+ emit_u16(s, 0);
+ emit_op(s, OP_drop);
+ }
+
pop_scope(s);
pop_scope(s);
@@ -23456,7 +23610,7 @@ static warn_unused int js_parse_class(JSParseState *s, BOOL is_class_expr,
return -1;
}
-static warn_unused int js_parse_array_literal(JSParseState *s)
+static __exception int js_parse_array_literal(JSParseState *s)
{
uint32_t idx;
BOOL need_length;
@@ -23492,7 +23646,7 @@ static warn_unused int js_parse_array_literal(JSParseState *s)
if (js_parse_assign_expr(s))
return -1;
emit_op(s, OP_define_field);
- emit_u32(s, JS_AtomFromUInt32(idx));
+ emit_u32(s, __JS_AtomFromUInt32(idx));
need_length = FALSE;
}
idx++;
@@ -23602,7 +23756,7 @@ static BOOL has_with_scope(JSFunctionDef *s, int scope_level)
return FALSE;
}
-static warn_unused int get_lvalue(JSParseState *s, int *popcode, int *pscope,
+static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
JSAtom *pname, int *plabel, int *pdepth, BOOL keep,
int tok)
{
@@ -23842,7 +23996,7 @@ static void put_lvalue(JSParseState *s, int opcode, int scope,
}
}
-static warn_unused int js_parse_expr_paren(JSParseState *s)
+static __exception int js_parse_expr_paren(JSParseState *s)
{
if (js_parse_expect(s, '('))
return -1;
@@ -23860,7 +24014,7 @@ static int js_unsupported_keyword(JSParseState *s, JSAtom atom)
JS_AtomGetStr(s->ctx, buf, sizeof(buf), atom));
}
-static warn_unused int js_define_var(JSParseState *s, JSAtom name, int tok)
+static __exception int js_define_var(JSParseState *s, JSAtom name, int tok)
{
JSFunctionDef *fd = s->cur_func;
JSVarDefEnum var_def_type;
@@ -24408,8 +24562,8 @@ static void optional_chain_test(JSParseState *s, int *poptional_chaining_label,
emit_label(s, label_next);
}
-/* allowed parse_flags: PF_POSTFIX_CALL, PF_ARROW_FUNC */
-static warn_unused int js_parse_postfix_expr(JSParseState *s, int parse_flags)
+/* allowed parse_flags: PF_POSTFIX_CALL */
+static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
{
FuncCallType call_type;
int optional_chaining_label;
@@ -24511,16 +24665,8 @@ static warn_unused int js_parse_postfix_expr(JSParseState *s, int parse_flags)
}
break;
case '(':
- if ((parse_flags & PF_ARROW_FUNC) &&
- js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) {
- if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
- JS_FUNC_NORMAL, JS_ATOM_NULL,
- s->token.ptr, s->token.line_num))
- return -1;
- } else {
- if (js_parse_expr_paren(s))
- return -1;
- }
+ if (js_parse_expr_paren(s))
+ return -1;
break;
case TOK_FUNCTION:
if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,
@@ -24560,14 +24706,8 @@ static warn_unused int js_parse_postfix_expr(JSParseState *s, int parse_flags)
if (s->token.u.ident.is_reserved) {
return js_parse_error_reserved_identifier(s);
}
- if ((parse_flags & PF_ARROW_FUNC) &&
- peek_token(s, TRUE) == TOK_ARROW) {
- if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
- JS_FUNC_NORMAL, JS_ATOM_NULL,
- s->token.ptr, s->token.line_num))
- return -1;
- } else if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
- peek_token(s, TRUE) != '\n') {
+ if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
+ peek_token(s, TRUE) != '\n') {
const uint8_t *source_ptr;
int source_line_num;
@@ -24580,15 +24720,6 @@ static warn_unused int js_parse_postfix_expr(JSParseState *s, int parse_flags)
JS_FUNC_ASYNC, JS_ATOM_NULL,
source_ptr, source_line_num))
return -1;
- } else if ((parse_flags & PF_ARROW_FUNC) &&
- ((s->token.val == '(' &&
- js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) ||
- (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
- peek_token(s, TRUE) == TOK_ARROW))) {
- if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
- JS_FUNC_ASYNC, JS_ATOM_NULL,
- source_ptr, source_line_num))
- return -1;
} else {
name = JS_DupAtom(s->ctx, JS_ATOM_async);
goto do_get_var;
@@ -24600,8 +24731,10 @@ static warn_unused int js_parse_postfix_expr(JSParseState *s, int parse_flags)
return -1;
}
name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
- if (next_token(s)) /* update line number before emitting code */
+ if (next_token(s)) { /* update line number before emitting code */
+ JS_FreeAtom(s->ctx, name);
return -1;
+ }
do_get_var:
emit_op(s, OP_scope_get_var);
emit_u32(s, name);
@@ -24748,6 +24881,25 @@ static warn_unused int js_parse_postfix_expr(JSParseState *s, int parse_flags)
fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
drop_count = 2;
break;
+ case OP_get_field_opt_chain:
+ {
+ int opt_chain_label, next_label;
+ opt_chain_label = get_u32(fd->byte_code.buf +
+ fd->last_opcode_pos + 1 + 4 + 1);
+ /* keep the object on the stack */
+ fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
+ fd->byte_code.size = fd->last_opcode_pos + 1 + 4;
+ next_label = emit_goto(s, OP_goto, -1);
+ emit_label(s, opt_chain_label);
+ /* need an additional undefined value for the
+ case where the optional field does not
+ exists */
+ emit_op(s, OP_undefined);
+ emit_label(s, next_label);
+ drop_count = 2;
+ opcode = OP_get_field;
+ }
+ break;
case OP_scope_get_private_field:
/* keep the object on the stack */
fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_private_field2;
@@ -24758,6 +24910,25 @@ static warn_unused int js_parse_postfix_expr(JSParseState *s, int parse_flags)
fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
drop_count = 2;
break;
+ case OP_get_array_el_opt_chain:
+ {
+ int opt_chain_label, next_label;
+ opt_chain_label = get_u32(fd->byte_code.buf +
+ fd->last_opcode_pos + 1 + 1);
+ /* keep the object on the stack */
+ fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
+ fd->byte_code.size = fd->last_opcode_pos + 1;
+ next_label = emit_goto(s, OP_goto, -1);
+ emit_label(s, opt_chain_label);
+ /* need an additional undefined value for the
+ case where the optional field does not
+ exists */
+ emit_op(s, OP_undefined);
+ emit_label(s, next_label);
+ drop_count = 2;
+ opcode = OP_get_array_el;
+ }
+ break;
case OP_scope_get_var:
{
JSAtom name;
@@ -25040,43 +25211,89 @@ static warn_unused int js_parse_postfix_expr(JSParseState *s, int parse_flags)
break;
}
}
- if (optional_chaining_label >= 0)
- emit_label(s, optional_chaining_label);
+ if (optional_chaining_label >= 0) {
+ JSFunctionDef *fd = s->cur_func;
+ int opcode;
+ emit_label_raw(s, optional_chaining_label);
+ /* modify the last opcode so that it is an indicator of an
+ optional chain */
+ opcode = get_prev_opcode(fd);
+ if (opcode == OP_get_field || opcode == OP_get_array_el) {
+ if (opcode == OP_get_field)
+ opcode = OP_get_field_opt_chain;
+ else
+ opcode = OP_get_array_el_opt_chain;
+ fd->byte_code.buf[fd->last_opcode_pos] = opcode;
+ } else {
+ fd->last_opcode_pos = -1;
+ }
+ }
return 0;
}
-static warn_unused int js_parse_delete(JSParseState *s)
+static __exception int js_parse_delete(JSParseState *s)
{
JSFunctionDef *fd = s->cur_func;
JSAtom name;
+ int opcode;
if (next_token(s))
return -1;
if (js_parse_unary(s, PF_POW_FORBIDDEN))
return -1;
- switch (get_prev_opcode(fd)) {
+ switch(opcode = get_prev_opcode(fd)) {
case OP_get_field:
+ case OP_get_field_opt_chain:
{
JSValue val;
- int ret;
-
+ int ret, opt_chain_label, next_label;
+ if (opcode == OP_get_field_opt_chain) {
+ opt_chain_label = get_u32(fd->byte_code.buf +
+ fd->last_opcode_pos + 1 + 4 + 1);
+ } else {
+ opt_chain_label = -1;
+ }
name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
fd->byte_code.size = fd->last_opcode_pos;
- fd->last_opcode_pos = -1;
val = JS_AtomToValue(s->ctx, name);
ret = emit_push_const(s, val, 1);
JS_FreeValue(s->ctx, val);
JS_FreeAtom(s->ctx, name);
if (ret)
return ret;
+ emit_op(s, OP_delete);
+ if (opt_chain_label >= 0) {
+ next_label = emit_goto(s, OP_goto, -1);
+ emit_label(s, opt_chain_label);
+ /* if the optional chain is not taken, return 'true' */
+ emit_op(s, OP_drop);
+ emit_op(s, OP_push_true);
+ emit_label(s, next_label);
+ }
+ fd->last_opcode_pos = -1;
}
- goto do_delete;
+ break;
case OP_get_array_el:
fd->byte_code.size = fd->last_opcode_pos;
fd->last_opcode_pos = -1;
- do_delete:
emit_op(s, OP_delete);
break;
+ case OP_get_array_el_opt_chain:
+ {
+ int opt_chain_label, next_label;
+ opt_chain_label = get_u32(fd->byte_code.buf +
+ fd->last_opcode_pos + 1 + 1);
+ fd->byte_code.size = fd->last_opcode_pos;
+ emit_op(s, OP_delete);
+ next_label = emit_goto(s, OP_goto, -1);
+ emit_label(s, opt_chain_label);
+ /* if the optional chain is not taken, return 'true' */
+ emit_op(s, OP_drop);
+ emit_op(s, OP_push_true);
+ emit_label(s, next_label);
+ fd->last_opcode_pos = -1;
+ }
+ break;
case OP_scope_get_var:
/* 'delete this': this is not a reference */
name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
@@ -25091,6 +25308,8 @@ static warn_unused int js_parse_delete(JSParseState *s)
case OP_scope_get_private_field:
return js_parse_error(s, "cannot delete a private class field");
case OP_get_super_value:
+ fd->byte_code.size = fd->last_opcode_pos;
+ fd->last_opcode_pos = -1;
emit_op(s, OP_throw_error);
emit_atom(s, JS_ATOM_NULL);
emit_u8(s, JS_THROW_ERROR_DELETE_SUPER);
@@ -25104,8 +25323,8 @@ static warn_unused int js_parse_delete(JSParseState *s)
return 0;
}
-/* allowed parse_flags: PF_ARROW_FUNC, PF_POW_ALLOWED, PF_POW_FORBIDDEN */
-static warn_unused int js_parse_unary(JSParseState *s, int parse_flags)
+/* allowed parse_flags: PF_POW_ALLOWED, PF_POW_FORBIDDEN */
+static __exception int js_parse_unary(JSParseState *s, int parse_flags)
{
int op;
@@ -25190,12 +25409,12 @@ static warn_unused int js_parse_unary(JSParseState *s, int parse_flags)
return -1;
if (js_parse_unary(s, PF_POW_FORBIDDEN))
return -1;
+ s->cur_func->has_await = TRUE;
emit_op(s, OP_await);
parse_flags = 0;
break;
default:
- if (js_parse_postfix_expr(s, (parse_flags & PF_ARROW_FUNC) |
- PF_POSTFIX_CALL))
+ if (js_parse_postfix_expr(s, PF_POSTFIX_CALL))
return -1;
if (!s->got_lf &&
(s->token.val == TOK_DEC || s->token.val == TOK_INC)) {
@@ -25252,18 +25471,40 @@ static warn_unused int js_parse_unary(JSParseState *s, int parse_flags)
return 0;
}
-/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
-static warn_unused int js_parse_expr_binary(JSParseState *s, int level,
+/* allowed parse_flags: PF_IN_ACCEPTED */
+static __exception int js_parse_expr_binary(JSParseState *s, int level,
int parse_flags)
{
int op, opcode;
if (level == 0) {
- return js_parse_unary(s, (parse_flags & PF_ARROW_FUNC) |
- PF_POW_ALLOWED);
+ return js_parse_unary(s, PF_POW_ALLOWED);
+ } else if (s->token.val == TOK_PRIVATE_NAME &&
+ (parse_flags & PF_IN_ACCEPTED) && level == 4 &&
+ peek_token(s, FALSE) == TOK_IN) {
+ JSAtom atom;
+
+ atom = JS_DupAtom(s->ctx, s->token.u.ident.atom);
+ if (next_token(s))
+ goto fail_private_in;
+ if (s->token.val != TOK_IN)
+ goto fail_private_in;
+ if (next_token(s))
+ goto fail_private_in;
+ if (js_parse_expr_binary(s, level - 1, parse_flags)) {
+ fail_private_in:
+ JS_FreeAtom(s->ctx, atom);
+ return -1;
+ }
+ emit_op(s, OP_scope_in_private_field);
+ emit_atom(s, atom);
+ emit_u16(s, s->cur_func->scope_level);
+ JS_FreeAtom(s->ctx, atom);
+ return 0;
+ } else {
+ if (js_parse_expr_binary(s, level - 1, parse_flags))
+ return -1;
}
- if (js_parse_expr_binary(s, level - 1, parse_flags))
- return -1;
for(;;) {
op = s->token.val;
switch(level) {
@@ -25392,15 +25633,15 @@ static warn_unused int js_parse_expr_binary(JSParseState *s, int level,
}
if (next_token(s))
return -1;
- if (js_parse_expr_binary(s, level - 1, parse_flags & ~PF_ARROW_FUNC))
+ if (js_parse_expr_binary(s, level - 1, parse_flags))
return -1;
emit_op(s, opcode);
}
return 0;
}
-/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
-static warn_unused int js_parse_logical_and_or(JSParseState *s, int op,
+/* allowed parse_flags: PF_IN_ACCEPTED */
+static __exception int js_parse_logical_and_or(JSParseState *s, int op,
int parse_flags)
{
int label1;
@@ -25423,11 +25664,11 @@ static warn_unused int js_parse_logical_and_or(JSParseState *s, int op,
emit_op(s, OP_drop);
if (op == TOK_LAND) {
- if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC))
+ if (js_parse_expr_binary(s, 8, parse_flags))
return -1;
} else {
if (js_parse_logical_and_or(s, TOK_LAND,
- parse_flags & ~PF_ARROW_FUNC))
+ parse_flags))
return -1;
}
if (s->token.val != op) {
@@ -25442,7 +25683,7 @@ static warn_unused int js_parse_logical_and_or(JSParseState *s, int op,
return 0;
}
-static warn_unused int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
+static __exception int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
{
int label1;
@@ -25459,7 +25700,7 @@ static warn_unused int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
emit_goto(s, OP_if_false, label1);
emit_op(s, OP_drop);
- if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC))
+ if (js_parse_expr_binary(s, 8, parse_flags))
return -1;
if (s->token.val != TOK_DOUBLE_QUESTION_MARK)
break;
@@ -25469,8 +25710,8 @@ static warn_unused int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
return 0;
}
-/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
-static warn_unused int js_parse_cond_expr(JSParseState *s, int parse_flags)
+/* allowed parse_flags: PF_IN_ACCEPTED */
+static __exception int js_parse_cond_expr(JSParseState *s, int parse_flags)
{
int label1, label2;
@@ -25501,7 +25742,7 @@ static warn_unused int js_parse_cond_expr(JSParseState *s, int parse_flags)
static void emit_return(JSParseState *s, BOOL hasval);
/* allowed parse_flags: PF_IN_ACCEPTED */
-static warn_unused int js_parse_assign_expr2(JSParseState *s, int parse_flags)
+static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
{
int opcode, op, scope;
JSAtom name0 = JS_ATOM_NULL;
@@ -25563,7 +25804,6 @@ static warn_unused int js_parse_assign_expr2(JSParseState *s, int parse_flags)
/* OP_async_yield_star takes the value as parameter */
emit_op(s, OP_get_field);
emit_atom(s, JS_ATOM_value);
- emit_op(s, OP_await);
emit_op(s, OP_async_yield_star);
} else {
/* OP_yield_star takes (value, done) as parameter */
@@ -25645,12 +25885,50 @@ static warn_unused int js_parse_assign_expr2(JSParseState *s, int parse_flags)
emit_label(s, label_next);
}
return 0;
+ } else if (s->token.val == '(' &&
+ js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) {
+ return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
+ JS_FUNC_NORMAL, JS_ATOM_NULL,
+ s->token.ptr, s->token.line_num);
+ } else if (token_is_pseudo_keyword(s, JS_ATOM_async)) {
+ const uint8_t *source_ptr;
+ int source_line_num, tok;
+ JSParsePos pos;
+
+ /* fast test */
+ tok = peek_token(s, TRUE);
+ if (tok == TOK_FUNCTION || tok == '\n')
+ goto next;
+
+ source_ptr = s->token.ptr;
+ source_line_num = s->token.line_num;
+ js_parse_get_pos(s, &pos);
+ if (next_token(s))
+ return -1;
+ if ((s->token.val == '(' &&
+ js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) ||
+ (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
+ peek_token(s, TRUE) == TOK_ARROW)) {
+ return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
+ JS_FUNC_ASYNC, JS_ATOM_NULL,
+ source_ptr, source_line_num);
+ } else {
+ /* undo the token parsing */
+ if (js_parse_seek_token(s, &pos))
+ return -1;
+ }
+ } else if (s->token.val == TOK_IDENT &&
+ peek_token(s, TRUE) == TOK_ARROW) {
+ return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
+ JS_FUNC_NORMAL, JS_ATOM_NULL,
+ s->token.ptr, s->token.line_num);
}
+ next:
if (s->token.val == TOK_IDENT) {
/* name0 is used to check for OP_set_name pattern, not duplicated */
name0 = s->token.u.ident.atom;
}
- if (js_parse_cond_expr(s, parse_flags | PF_ARROW_FUNC))
+ if (js_parse_cond_expr(s, parse_flags))
return -1;
op = s->token.val;
@@ -25747,13 +26025,13 @@ static warn_unused int js_parse_assign_expr2(JSParseState *s, int parse_flags)
return 0;
}
-static warn_unused int js_parse_assign_expr(JSParseState *s)
+static __exception int js_parse_assign_expr(JSParseState *s)
{
return js_parse_assign_expr2(s, PF_IN_ACCEPTED);
}
/* allowed parse_flags: PF_IN_ACCEPTED */
-static warn_unused int js_parse_expr2(JSParseState *s, int parse_flags)
+static __exception int js_parse_expr2(JSParseState *s, int parse_flags)
{
BOOL comma = FALSE;
for(;;) {
@@ -25777,7 +26055,7 @@ static warn_unused int js_parse_expr2(JSParseState *s, int parse_flags)
return 0;
}
-static warn_unused int js_parse_expr(JSParseState *s)
+static __exception int js_parse_expr(JSParseState *s)
{
return js_parse_expr2(s, PF_IN_ACCEPTED);
}
@@ -25805,7 +26083,7 @@ static void pop_break_entry(JSFunctionDef *fd)
fd->top_break = be->prev;
}
-static warn_unused int emit_break(JSParseState *s, JSAtom name, int is_cont)
+static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont)
{
BlockEnv *top;
int i, scope_level;
@@ -25857,61 +26135,61 @@ static warn_unused int emit_break(JSParseState *s, JSAtom name, int is_cont)
static void emit_return(JSParseState *s, BOOL hasval)
{
BlockEnv *top;
- int drop_count;
- drop_count = 0;
+ if (s->cur_func->func_kind != JS_FUNC_NORMAL) {
+ if (!hasval) {
+ /* no value: direct return in case of async generator */
+ emit_op(s, OP_undefined);
+ hasval = TRUE;
+ } else if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
+ /* the await must be done before handling the "finally" in
+ case it raises an exception */
+ emit_op(s, OP_await);
+ }
+ }
+
top = s->cur_func->top_break;
while (top != NULL) {
- /* XXX: emit the appropriate OP_leave_scope opcodes? Probably not
- required as all local variables will be closed upon returning
- from JS_CallInternal, but not in the same order. */
- if (top->has_iterator) {
- /* with 'yield', the exact number of OP_drop to emit is
- unknown, so we use a specific operation to look for
- the catch offset */
+ if (top->has_iterator || top->label_finally != -1) {
if (!hasval) {
emit_op(s, OP_undefined);
hasval = TRUE;
}
- emit_op(s, OP_iterator_close_return);
- if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
- int label_next, label_next2;
-
- emit_op(s, OP_drop); /* catch offset */
- emit_op(s, OP_drop); /* next */
- emit_op(s, OP_get_field2);
- emit_atom(s, JS_ATOM_return);
- /* stack: iter_obj return_func */
- emit_op(s, OP_dup);
- emit_op(s, OP_is_undefined_or_null);
- label_next = emit_goto(s, OP_if_true, -1);
- emit_op(s, OP_call_method);
- emit_u16(s, 0);
- emit_op(s, OP_iterator_check_object);
- emit_op(s, OP_await);
- label_next2 = emit_goto(s, OP_goto, -1);
- emit_label(s, label_next);
- emit_op(s, OP_drop);
- emit_label(s, label_next2);
- emit_op(s, OP_drop);
+ /* Remove the stack elements up to and including the catch
+ offset. When 'yield' is used in an expression we have
+ no easy way to count them, so we use this specific
+ instruction instead. */
+ emit_op(s, OP_nip_catch);
+ /* stack: iter_obj next ret_val */
+ if (top->has_iterator) {
+ if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
+ int label_next, label_next2;
+ emit_op(s, OP_nip); /* next */
+ emit_op(s, OP_swap);
+ emit_op(s, OP_get_field2);
+ emit_atom(s, JS_ATOM_return);
+ /* stack: iter_obj return_func */
+ emit_op(s, OP_dup);
+ emit_op(s, OP_is_undefined_or_null);
+ label_next = emit_goto(s, OP_if_true, -1);
+ emit_op(s, OP_call_method);
+ emit_u16(s, 0);
+ emit_op(s, OP_iterator_check_object);
+ emit_op(s, OP_await);
+ label_next2 = emit_goto(s, OP_goto, -1);
+ emit_label(s, label_next);
+ emit_op(s, OP_drop);
+ emit_label(s, label_next2);
+ emit_op(s, OP_drop);
+ } else {
+ emit_op(s, OP_rot3r);
+ emit_op(s, OP_undefined); /* dummy catch offset */
+ emit_op(s, OP_iterator_close);
+ }
} else {
- emit_op(s, OP_iterator_close);
+ /* execute the "finally" block */
+ emit_goto(s, OP_gosub, top->label_finally);
}
- drop_count = -3;
- }
- drop_count += top->drop_count;
- if (top->label_finally != -1) {
- while(drop_count) {
- /* must keep the stack top if hasval */
- emit_op(s, hasval ? OP_nip : OP_drop);
- drop_count--;
- }
- if (!hasval) {
- /* must push return value to keep same stack size */
- emit_op(s, OP_undefined);
- hasval = TRUE;
- }
- emit_goto(s, OP_gosub, top->label_finally);
}
top = top->prev;
}
@@ -25928,20 +26206,15 @@ static void emit_return(JSParseState *s, BOOL hasval)
label_return = -1;
}
- /* XXX: if this is not initialized, should throw the
- ReferenceError in the caller realm */
- emit_op(s, OP_scope_get_var);
+ /* The error should be raised in the caller context, so we use
+ a specific opcode */
+ emit_op(s, OP_scope_get_var_checkthis);
emit_atom(s, JS_ATOM_this);
emit_u16(s, 0);
emit_label(s, label_return);
emit_op(s, OP_return);
} else if (s->cur_func->func_kind != JS_FUNC_NORMAL) {
- if (!hasval) {
- emit_op(s, OP_undefined);
- } else if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
- emit_op(s, OP_await);
- }
emit_op(s, OP_return_async);
} else {
emit_op(s, hasval ? OP_return : OP_return_undef);
@@ -25954,15 +26227,15 @@ static void emit_return(JSParseState *s, BOOL hasval)
#define DECL_MASK_OTHER (1 << 2) /* all other declarations */
#define DECL_MASK_ALL (DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL | DECL_MASK_OTHER)
-static warn_unused int js_parse_statement_or_decl(JSParseState *s,
+static __exception int js_parse_statement_or_decl(JSParseState *s,
int decl_mask);
-static warn_unused int js_parse_statement(JSParseState *s)
+static __exception int js_parse_statement(JSParseState *s)
{
return js_parse_statement_or_decl(s, 0);
}
-static warn_unused int js_parse_block(JSParseState *s)
+static __exception int js_parse_block(JSParseState *s)
{
if (js_parse_expect(s, '{'))
return -1;
@@ -25982,7 +26255,7 @@ static warn_unused int js_parse_block(JSParseState *s)
}
/* allowed parse_flags: PF_IN_ACCEPTED */
-static warn_unused int js_parse_var(JSParseState *s, int parse_flags, int tok,
+static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
BOOL export_flag)
{
JSContext *ctx = s->ctx;
@@ -26088,7 +26361,6 @@ static int is_let(JSParseState *s, int decl_mask)
int res = FALSE;
if (token_is_pseudo_keyword(s, JS_ATOM_let)) {
-#if 1
JSParsePos pos;
js_parse_get_pos(s, &pos);
for (;;) {
@@ -26121,19 +26393,13 @@ static int is_let(JSParseState *s, int decl_mask)
if (js_parse_seek_token(s, &pos)) {
res = -1;
}
-#else
- int tok = peek_token(s, TRUE);
- if (tok == '{' || tok == TOK_IDENT || peek_token(s, FALSE) == '[') {
- res = TRUE;
- }
-#endif
}
return res;
}
/* XXX: handle IteratorClose when exiting the loop before the
enumeration is done */
-static warn_unused int js_parse_for_in_of(JSParseState *s, int label_name,
+static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
BOOL is_async)
{
JSContext *ctx = s->ctx;
@@ -26208,6 +26474,9 @@ static warn_unused int js_parse_for_in_of(JSParseState *s, int label_name,
emit_atom(s, var_name);
emit_u16(s, fd->scope_level);
}
+ } else if (!is_async && token_is_pseudo_keyword(s, JS_ATOM_async) &&
+ peek_token(s, FALSE) == TOK_OF) {
+ return js_parse_error(s, "'for of' expression cannot start with 'async'");
} else {
int skip_bits;
if ((s->token.val == '[' || s->token.val == '{')
@@ -26364,7 +26633,7 @@ static void set_eval_ret_undefined(JSParseState *s)
}
}
-static warn_unused int js_parse_statement_or_decl(JSParseState *s,
+static __exception int js_parse_statement_or_decl(JSParseState *s,
int decl_mask)
{
JSContext *ctx = s->ctx;
@@ -26424,6 +26693,10 @@ static warn_unused int js_parse_statement_or_decl(JSParseState *s,
js_parse_error(s, "return not in a function");
goto fail;
}
+ if (s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) {
+ js_parse_error(s, "return in a static initializer block");
+ goto fail;
+ }
if (next_token(s))
goto fail;
if (s->token.val != ';' && s->token.val != '}' && !s->got_lf) {
@@ -26592,6 +26865,7 @@ static warn_unused int js_parse_statement_or_decl(JSParseState *s,
is_async = TRUE;
if (next_token(s))
goto fail;
+ s->cur_func->has_await = TRUE;
}
if (js_parse_expect(s, '('))
goto fail;
@@ -27122,6 +27396,9 @@ static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name)
m->func_obj = JS_UNDEFINED;
m->eval_exception = JS_UNDEFINED;
m->meta_obj = JS_UNDEFINED;
+ m->promise = JS_UNDEFINED;
+ m->resolving_funcs[0] = JS_UNDEFINED;
+ m->resolving_funcs[1] = JS_UNDEFINED;
list_add_tail(&m->link, &ctx->loaded_modules);
return m;
}
@@ -27143,6 +27420,9 @@ static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
JS_MarkValue(rt, m->func_obj, mark_func);
JS_MarkValue(rt, m->eval_exception, mark_func);
JS_MarkValue(rt, m->meta_obj, mark_func);
+ JS_MarkValue(rt, m->promise, mark_func);
+ JS_MarkValue(rt, m->resolving_funcs[0], mark_func);
+ JS_MarkValue(rt, m->resolving_funcs[1], mark_func);
}
static void js_free_module_def(JSContext *ctx, JSModuleDef *m)
@@ -27173,11 +27453,15 @@ static void js_free_module_def(JSContext *ctx, JSModuleDef *m)
JS_FreeAtom(ctx, mi->import_name);
}
js_free(ctx, m->import_entries);
+ js_free(ctx, m->async_parent_modules);
JS_FreeValue(ctx, m->module_ns);
JS_FreeValue(ctx, m->func_obj);
JS_FreeValue(ctx, m->eval_exception);
JS_FreeValue(ctx, m->meta_obj);
+ JS_FreeValue(ctx, m->promise);
+ JS_FreeValue(ctx, m->resolving_funcs[0]);
+ JS_FreeValue(ctx, m->resolving_funcs[1]);
list_del(&m->link);
js_free(ctx, m);
}
@@ -27338,6 +27622,7 @@ static char *js_default_module_normalize_name(JSContext *ctx,
{
char *filename, *p;
const char *r;
+ int cap;
int len;
if (name[0] != '.') {
@@ -27351,7 +27636,8 @@ static char *js_default_module_normalize_name(JSContext *ctx,
else
len = 0;
- filename = js_malloc(ctx, len + strlen(name) + 1 + 1);
+ cap = len + strlen(name) + 1 + 1;
+ filename = js_malloc(ctx, cap);
if (!filename)
return NULL;
memcpy(filename, base_name, len);
@@ -27383,8 +27669,8 @@ static char *js_default_module_normalize_name(JSContext *ctx,
}
}
if (filename[0] != '\0')
- strcat(filename, "/");
- strcat(filename, r);
+ pstrcat(filename, cap, "/");
+ pstrcat(filename, cap, r);
// printf("normalize: %s %s -> %s\n", base_name, name, filename);
return filename;
}
@@ -27684,7 +27970,7 @@ static int find_exported_name(GetExportNamesState *s, JSAtom name)
return -1;
}
-static warn_unused int get_exported_names(JSContext *ctx,
+static __exception int get_exported_names(JSContext *ctx,
GetExportNamesState *s,
JSModuleDef *m, BOOL from_star)
{
@@ -27766,13 +28052,11 @@ static int exported_names_cmp(const void *p1, const void *p2, void *opaque)
return ret;
}
-static JSValue js_get_module_ns(JSContext *ctx, JSModuleDef *m);
-
static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
void *opaque)
{
JSModuleDef *m = opaque;
- return js_get_module_ns(ctx, m);
+ return JS_GetModuleNamespace(ctx, m);
}
static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)
@@ -27877,7 +28161,7 @@ static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)
return JS_EXCEPTION;
}
-static JSValue js_get_module_ns(JSContext *ctx, JSModuleDef *m)
+JSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m)
{
if (JS_IsUndefined(m->module_ns)) {
JSValue val;
@@ -28032,7 +28316,8 @@ static int js_create_module_function(JSContext *ctx, JSModuleDef *m)
/* Prepare a module to be executed by resolving all the imported
variables. */
-static int js_link_module(JSContext *ctx, JSModuleDef *m)
+static int js_inner_module_linking(JSContext *ctx, JSModuleDef *m,
+ JSModuleDef **pstack_top, int index)
{
int i;
JSImportEntry *mi;
@@ -28042,21 +28327,47 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m)
BOOL is_c_module;
JSValue ret_val;
- if (m->instantiated)
- return 0;
- m->instantiated = TRUE;
+ if (js_check_stack_overflow(ctx->rt, 0)) {
+ JS_ThrowStackOverflow(ctx);
+ return -1;
+ }
#ifdef DUMP_MODULE_RESOLVE
{
char buf1[ATOM_GET_STR_BUF_SIZE];
- printf("start instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
+ printf("js_inner_module_linking '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
}
#endif
+ if (m->status == JS_MODULE_STATUS_LINKING ||
+ m->status == JS_MODULE_STATUS_LINKED ||
+ m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m->status == JS_MODULE_STATUS_EVALUATED)
+ return index;
+
+ assert(m->status == JS_MODULE_STATUS_UNLINKED);
+ m->status = JS_MODULE_STATUS_LINKING;
+ m->dfs_index = index;
+ m->dfs_ancestor_index = index;
+ index++;
+ /* push 'm' on stack */
+ m->stack_prev = *pstack_top;
+ *pstack_top = m;
+
for(i = 0; i < m->req_module_entries_count; i++) {
JSReqModuleEntry *rme = &m->req_module_entries[i];
- if (js_link_module(ctx, rme->module) < 0)
+ m1 = rme->module;
+ index = js_inner_module_linking(ctx, m1, pstack_top, index);
+ if (index < 0)
goto fail;
+ assert(m1->status == JS_MODULE_STATUS_LINKING ||
+ m1->status == JS_MODULE_STATUS_LINKED ||
+ m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m1->status == JS_MODULE_STATUS_EVALUATED);
+ if (m1->status == JS_MODULE_STATUS_LINKING) {
+ m->dfs_ancestor_index = min_int(m->dfs_ancestor_index,
+ m1->dfs_ancestor_index);
+ }
}
#ifdef DUMP_MODULE_RESOLVE
@@ -28111,7 +28422,7 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m)
if (mi->import_name == JS_ATOM__star_) {
JSValue val;
/* name space import */
- val = js_get_module_ns(ctx, m1);
+ val = JS_GetModuleNamespace(ctx, m1);
if (JS_IsException(val))
goto fail;
set_value(ctx, &var_refs[mi->var_idx]->value, val);
@@ -28135,7 +28446,7 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m)
JSModuleDef *m2;
/* name space import from */
m2 = res_m->req_module_entries[res_me->u.req_module_idx].module;
- val = js_get_module_ns(ctx, m2);
+ val = JS_GetModuleNamespace(ctx, m2);
if (JS_IsException(val))
goto fail;
var_ref = js_create_module_var(ctx, TRUE);
@@ -28182,14 +28493,59 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m)
JS_FreeValue(ctx, ret_val);
}
+ assert(m->dfs_ancestor_index <= m->dfs_index);
+ if (m->dfs_index == m->dfs_ancestor_index) {
+ for(;;) {
+ /* pop m1 from stack */
+ m1 = *pstack_top;
+ *pstack_top = m1->stack_prev;
+ m1->status = JS_MODULE_STATUS_LINKED;
+ if (m1 == m)
+ break;
+ }
+ }
+
#ifdef DUMP_MODULE_RESOLVE
- printf("done instantiate\n");
+ printf("js_inner_module_linking done\n");
#endif
- return 0;
+ return index;
fail:
return -1;
}
+/* Prepare a module to be executed by resolving all the imported
+ variables. */
+static int js_link_module(JSContext *ctx, JSModuleDef *m)
+{
+ JSModuleDef *stack_top, *m1;
+
+#ifdef DUMP_MODULE_RESOLVE
+ {
+ char buf1[ATOM_GET_STR_BUF_SIZE];
+ printf("js_link_module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
+ }
+#endif
+ assert(m->status == JS_MODULE_STATUS_UNLINKED ||
+ m->status == JS_MODULE_STATUS_LINKED ||
+ m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m->status == JS_MODULE_STATUS_EVALUATED);
+ stack_top = NULL;
+ if (js_inner_module_linking(ctx, m, &stack_top, 0) < 0) {
+ while (stack_top != NULL) {
+ m1 = stack_top;
+ assert(m1->status == JS_MODULE_STATUS_LINKING);
+ m1->status = JS_MODULE_STATUS_UNLINKED;
+ stack_top = m1->stack_prev;
+ }
+ return -1;
+ }
+ assert(stack_top == NULL);
+ assert(m->status == JS_MODULE_STATUS_LINKED ||
+ m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m->status == JS_MODULE_STATUS_EVALUATED);
+ return 0;
+}
+
/* return JS_ATOM_NULL if the name cannot be found. Only works with
not striped bytecode functions. */
JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels)
@@ -28198,8 +28554,8 @@ JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels)
JSFunctionBytecode *b;
JSObject *p;
/* XXX: currently we just use the filename of the englobing
- function. It does not work for eval(). Need to add a
- ScriptOrModule info in JSFunctionBytecode */
+ function from the debug info. May need to add a ScriptOrModule
+ info in JSFunctionBytecode. */
sf = ctx->rt->current_stack_frame;
if (!sf)
return JS_ATOM_NULL;
@@ -28208,15 +28564,23 @@ JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels)
if (!sf)
return JS_ATOM_NULL;
}
- if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT)
- return JS_ATOM_NULL;
- p = JS_VALUE_GET_OBJ(sf->cur_func);
- if (!js_class_has_bytecode(p->class_id))
- return JS_ATOM_NULL;
- b = p->u.func.function_bytecode;
- if (!b->has_debug)
- return JS_ATOM_NULL;
- return JS_DupAtom(ctx, b->debug.filename);
+ for(;;) {
+ if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT)
+ return JS_ATOM_NULL;
+ p = JS_VALUE_GET_OBJ(sf->cur_func);
+ if (!js_class_has_bytecode(p->class_id))
+ return JS_ATOM_NULL;
+ b = p->u.func.function_bytecode;
+ if (!b->is_direct_or_indirect_eval) {
+ if (!b->has_debug)
+ return JS_ATOM_NULL;
+ return JS_DupAtom(ctx, b->debug.filename);
+ } else {
+ sf = sf->prev_frame;
+ if (!sf)
+ return JS_ATOM_NULL;
+ }
+ }
}
JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m)
@@ -28259,29 +28623,110 @@ static JSValue js_import_meta(JSContext *ctx)
return JS_GetImportMeta(ctx, m);
}
-/* used by os.Worker() and import() */
-JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
- const char *filename)
+static JSValue JS_NewModuleValue(JSContext *ctx, JSModuleDef *m)
+{
+ return JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
+}
+
+static JSValue js_load_module_rejected(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int magic, JSValue *func_data)
{
+ JSValueConst *resolving_funcs = (JSValueConst *)func_data;
+ JSValueConst error;
+ JSValue ret;
+
+ /* XXX: check if the test is necessary */
+ if (argc >= 1)
+ error = argv[0];
+ else
+ error = JS_UNDEFINED;
+ ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
+ 1, &error);
+ JS_FreeValue(ctx, ret);
+ return JS_UNDEFINED;
+}
+
+static JSValue js_load_module_fulfilled(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int magic, JSValue *func_data)
+{
+ JSValueConst *resolving_funcs = (JSValueConst *)func_data;
+ JSModuleDef *m = JS_VALUE_GET_PTR(func_data[2]);
+ JSValue ret, ns;
+
+ /* return the module namespace */
+ ns = JS_GetModuleNamespace(ctx, m);
+ if (JS_IsException(ns)) {
+ JSValue err = JS_GetException(ctx);
+ js_load_module_rejected(ctx, JS_UNDEFINED, 1, (JSValueConst *)&err, 0, func_data);
+ return JS_UNDEFINED;
+ }
+ ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED,
+ 1, (JSValueConst *)&ns);
+ JS_FreeValue(ctx, ret);
+ JS_FreeValue(ctx, ns);
+ return JS_UNDEFINED;
+}
+
+static void JS_LoadModuleInternal(JSContext *ctx, const char *basename,
+ const char *filename,
+ JSValueConst *resolving_funcs)
+{
+ JSValue evaluate_promise;
JSModuleDef *m;
- JSValue ret, func_obj;
+ JSValue ret, err, func_obj, evaluate_resolving_funcs[2];
+ JSValueConst func_data[3];
m = js_host_resolve_imported_module(ctx, basename, filename);
if (!m)
- return NULL;
+ goto fail;
if (js_resolve_module(ctx, m) < 0) {
js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
- return NULL;
+ goto fail;
}
/* Evaluate the module code */
- func_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
- ret = JS_EvalFunction(ctx, func_obj);
- if (JS_IsException(ret))
- return NULL;
+ func_obj = JS_NewModuleValue(ctx, m);
+ evaluate_promise = JS_EvalFunction(ctx, func_obj);
+ if (JS_IsException(evaluate_promise)) {
+ fail:
+ err = JS_GetException(ctx);
+ ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
+ 1, (JSValueConst *)&err);
+ JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
+ JS_FreeValue(ctx, err);
+ return;
+ }
+
+ func_obj = JS_NewModuleValue(ctx, m);
+ func_data[0] = resolving_funcs[0];
+ func_data[1] = resolving_funcs[1];
+ func_data[2] = func_obj;
+ evaluate_resolving_funcs[0] = JS_NewCFunctionData(ctx, js_load_module_fulfilled, 0, 0, 3, func_data);
+ evaluate_resolving_funcs[1] = JS_NewCFunctionData(ctx, js_load_module_rejected, 0, 0, 3, func_data);
+ JS_FreeValue(ctx, func_obj);
+ ret = js_promise_then(ctx, evaluate_promise, 2, (JSValueConst *)evaluate_resolving_funcs);
JS_FreeValue(ctx, ret);
- return m;
+ JS_FreeValue(ctx, evaluate_resolving_funcs[0]);
+ JS_FreeValue(ctx, evaluate_resolving_funcs[1]);
+ JS_FreeValue(ctx, evaluate_promise);
+}
+
+/* Return a promise or an exception in case of memory error. Used by
+ os.Worker() */
+JSValue JS_LoadModule(JSContext *ctx, const char *basename,
+ const char *filename)
+{
+ JSValue promise, resolving_funcs[2];
+
+ promise = JS_NewPromiseCapability(ctx, resolving_funcs);
+ if (JS_IsException(promise))
+ return JS_EXCEPTION;
+ JS_LoadModuleInternal(ctx, basename, filename,
+ (JSValueConst *)resolving_funcs);
+ JS_FreeValue(ctx, resolving_funcs[0]);
+ JS_FreeValue(ctx, resolving_funcs[1]);
+ return promise;
}
static JSValue js_dynamic_import_job(JSContext *ctx,
@@ -28290,9 +28735,8 @@ static JSValue js_dynamic_import_job(JSContext *ctx,
JSValueConst *resolving_funcs = argv;
JSValueConst basename_val = argv[2];
JSValueConst specifier = argv[3];
- JSModuleDef *m;
const char *basename = NULL, *filename;
- JSValue ret, err, ns;
+ JSValue ret, err;
if (!JS_IsString(basename_val)) {
JS_ThrowTypeError(ctx, "no function filename for import()");
@@ -28306,27 +28750,15 @@ static JSValue js_dynamic_import_job(JSContext *ctx,
if (!filename)
goto exception;
- m = JS_RunModule(ctx, basename, filename);
+ JS_LoadModuleInternal(ctx, basename, filename,
+ resolving_funcs);
JS_FreeCString(ctx, filename);
- if (!m)
- goto exception;
-
- /* return the module namespace */
- ns = js_get_module_ns(ctx, m);
- if (JS_IsException(ns))
- goto exception;
-
- ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED,
- 1, &ns);
- JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
- JS_FreeValue(ctx, ns);
JS_FreeCString(ctx, basename);
return JS_UNDEFINED;
exception:
-
err = JS_GetException(ctx);
ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
- 1, &err);
+ 1, (JSValueConst *)&err);
JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
JS_FreeValue(ctx, err);
JS_FreeCString(ctx, basename);
@@ -28359,6 +28791,8 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier)
args[2] = basename_val;
args[3] = specifier;
+ /* cannot run JS_LoadModuleInternal synchronously because it would
+ cause an unexpected recursion in js_evaluate_module() */
JS_EnqueueJob(ctx, js_dynamic_import_job, 4, args);
JS_FreeValue(ctx, basename_val);
@@ -28367,63 +28801,400 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier)
return promise;
}
-/* Run the <eval> function of the module and of all its requested
- modules. */
-static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m)
+static void js_set_module_evaluated(JSContext *ctx, JSModuleDef *m)
+{
+ m->status = JS_MODULE_STATUS_EVALUATED;
+ if (!JS_IsUndefined(m->promise)) {
+ JSValue value, ret_val;
+ assert(m->cycle_root == m);
+ value = JS_UNDEFINED;
+ ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED,
+ 1, (JSValueConst *)&value);
+ JS_FreeValue(ctx, ret_val);
+ }
+}
+
+typedef struct {
+ JSModuleDef **tab;
+ int count;
+ int size;
+} ExecModuleList;
+
+/* XXX: slow. Could use a linked list instead of ExecModuleList */
+static BOOL find_in_exec_module_list(ExecModuleList *exec_list, JSModuleDef *m)
+{
+ int i;
+ for(i = 0; i < exec_list->count; i++) {
+ if (exec_list->tab[i] == m)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static int gather_available_ancestors(JSContext *ctx, JSModuleDef *module,
+ ExecModuleList *exec_list)
+{
+ int i;
+
+ if (js_check_stack_overflow(ctx->rt, 0)) {
+ JS_ThrowStackOverflow(ctx);
+ return -1;
+ }
+ for(i = 0; i < module->async_parent_modules_count; i++) {
+ JSModuleDef *m = module->async_parent_modules[i];
+ if (!find_in_exec_module_list(exec_list, m) &&
+ !m->cycle_root->eval_has_exception) {
+ assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC);
+ assert(!m->eval_has_exception);
+ assert(m->async_evaluation);
+ assert(m->pending_async_dependencies > 0);
+ m->pending_async_dependencies--;
+ if (m->pending_async_dependencies == 0) {
+ if (js_resize_array(ctx, (void **)&exec_list->tab, sizeof(exec_list->tab[0]), &exec_list->size, exec_list->count + 1)) {
+ return -1;
+ }
+ exec_list->tab[exec_list->count++] = m;
+ if (!m->has_tla) {
+ if (gather_available_ancestors(ctx, m, exec_list))
+ return -1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int exec_module_list_cmp(const void *p1, const void *p2, void *opaque)
+{
+ JSModuleDef *m1 = *(JSModuleDef **)p1;
+ JSModuleDef *m2 = *(JSModuleDef **)p2;
+ return (m1->async_evaluation_timestamp > m2->async_evaluation_timestamp) -
+ (m1->async_evaluation_timestamp < m2->async_evaluation_timestamp);
+}
+
+static int js_execute_async_module(JSContext *ctx, JSModuleDef *m);
+static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m,
+ JSValue *pvalue);
+
+static JSValue js_async_module_execution_rejected(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int magic, JSValue *func_data)
+{
+ JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]);
+ JSValueConst error = argv[0];
+ int i;
+
+ if (js_check_stack_overflow(ctx->rt, 0))
+ return JS_ThrowStackOverflow(ctx);
+
+ if (module->status == JS_MODULE_STATUS_EVALUATED) {
+ assert(module->eval_has_exception);
+ return JS_UNDEFINED;
+ }
+
+ assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC);
+ assert(!module->eval_has_exception);
+ assert(module->async_evaluation);
+
+ module->eval_has_exception = TRUE;
+ module->eval_exception = JS_DupValue(ctx, error);
+ module->status = JS_MODULE_STATUS_EVALUATED;
+
+ for(i = 0; i < module->async_parent_modules_count; i++) {
+ JSModuleDef *m = module->async_parent_modules[i];
+ JSValue m_obj = JS_NewModuleValue(ctx, m);
+ js_async_module_execution_rejected(ctx, JS_UNDEFINED, 1, &error, 0,
+ &m_obj);
+ JS_FreeValue(ctx, m_obj);
+ }
+
+ if (!JS_IsUndefined(module->promise)) {
+ JSValue ret_val;
+ assert(module->cycle_root == module);
+ ret_val = JS_Call(ctx, module->resolving_funcs[1], JS_UNDEFINED,
+ 1, &error);
+ JS_FreeValue(ctx, ret_val);
+ }
+ return JS_UNDEFINED;
+}
+
+static JSValue js_async_module_execution_fulfilled(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int magic, JSValue *func_data)
+{
+ JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]);
+ ExecModuleList exec_list_s, *exec_list = &exec_list_s;
+ int i;
+
+ if (module->status == JS_MODULE_STATUS_EVALUATED) {
+ assert(module->eval_has_exception);
+ return JS_UNDEFINED;
+ }
+ assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC);
+ assert(!module->eval_has_exception);
+ assert(module->async_evaluation);
+ module->async_evaluation = FALSE;
+ js_set_module_evaluated(ctx, module);
+
+ exec_list->tab = NULL;
+ exec_list->count = 0;
+ exec_list->size = 0;
+
+ if (gather_available_ancestors(ctx, module, exec_list) < 0) {
+ js_free(ctx, exec_list->tab);
+ return JS_EXCEPTION;
+ }
+
+ /* sort by increasing async_evaluation timestamp */
+ rqsort(exec_list->tab, exec_list->count, sizeof(exec_list->tab[0]),
+ exec_module_list_cmp, NULL);
+
+ for(i = 0; i < exec_list->count; i++) {
+ JSModuleDef *m = exec_list->tab[i];
+ if (m->status == JS_MODULE_STATUS_EVALUATED) {
+ assert(m->eval_has_exception);
+ } else if (m->has_tla) {
+ js_execute_async_module(ctx, m);
+ } else {
+ JSValue error;
+ if (js_execute_sync_module(ctx, m, &error) < 0) {
+ JSValue m_obj = JS_NewModuleValue(ctx, m);
+ js_async_module_execution_rejected(ctx, JS_UNDEFINED,
+ 1, (JSValueConst *)&error, 0,
+ &m_obj);
+ JS_FreeValue(ctx, m_obj);
+ JS_FreeValue(ctx, error);
+ } else {
+ js_set_module_evaluated(ctx, m);
+ }
+ }
+ }
+ js_free(ctx, exec_list->tab);
+ return JS_UNDEFINED;
+}
+
+static int js_execute_async_module(JSContext *ctx, JSModuleDef *m)
+{
+ JSValue promise, m_obj;
+ JSValue resolve_funcs[2], ret_val;
+ promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0);
+ if (JS_IsException(promise))
+ return -1;
+ m_obj = JS_NewModuleValue(ctx, m);
+ resolve_funcs[0] = JS_NewCFunctionData(ctx, js_async_module_execution_fulfilled, 0, 0, 1, (JSValueConst *)&m_obj);
+ resolve_funcs[1] = JS_NewCFunctionData(ctx, js_async_module_execution_rejected, 0, 0, 1, (JSValueConst *)&m_obj);
+ ret_val = js_promise_then(ctx, promise, 2, (JSValueConst *)resolve_funcs);
+ JS_FreeValue(ctx, ret_val);
+ JS_FreeValue(ctx, m_obj);
+ JS_FreeValue(ctx, resolve_funcs[0]);
+ JS_FreeValue(ctx, resolve_funcs[1]);
+ JS_FreeValue(ctx, promise);
+ return 0;
+}
+
+/* return < 0 in case of exception. *pvalue contains the exception. */
+static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m,
+ JSValue *pvalue)
+{
+ if (m->init_func) {
+ /* C module init : no asynchronous execution */
+ if (m->init_func(ctx, m) < 0)
+ goto fail;
+ } else {
+ JSValue promise;
+ JSPromiseStateEnum state;
+
+ promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0);
+ if (JS_IsException(promise))
+ goto fail;
+ state = JS_PromiseState(ctx, promise);
+ if (state == JS_PROMISE_FULFILLED) {
+ JS_FreeValue(ctx, promise);
+ } else if (state == JS_PROMISE_REJECTED) {
+ *pvalue = JS_PromiseResult(ctx, promise);
+ JS_FreeValue(ctx, promise);
+ return -1;
+ } else {
+ JS_FreeValue(ctx, promise);
+ JS_ThrowTypeError(ctx, "promise is pending");
+ fail:
+ *pvalue = JS_GetException(ctx);
+ return -1;
+ }
+ }
+ *pvalue = JS_UNDEFINED;
+ return 0;
+}
+
+/* spec: InnerModuleEvaluation. Return (index, JS_UNDEFINED) or (-1,
+ exception) */
+static int js_inner_module_evaluation(JSContext *ctx, JSModuleDef *m,
+ int index, JSModuleDef **pstack_top,
+ JSValue *pvalue)
{
JSModuleDef *m1;
int i;
- JSValue ret_val;
- if (m->eval_mark)
- return JS_UNDEFINED; /* avoid cycles */
+ if (js_check_stack_overflow(ctx->rt, 0)) {
+ JS_ThrowStackOverflow(ctx);
+ *pvalue = JS_GetException(ctx);
+ return -1;
+ }
+
+#ifdef DUMP_MODULE_RESOLVE
+ {
+ char buf1[ATOM_GET_STR_BUF_SIZE];
+ printf("js_inner_module_evaluation '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
+ }
+#endif
- if (m->evaluated) {
- /* if the module was already evaluated, rethrow the exception
- it raised */
+ if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m->status == JS_MODULE_STATUS_EVALUATED) {
if (m->eval_has_exception) {
- return JS_Throw(ctx, JS_DupValue(ctx, m->eval_exception));
+ *pvalue = JS_DupValue(ctx, m->eval_exception);
+ return -1;
} else {
- return JS_UNDEFINED;
+ *pvalue = JS_UNDEFINED;
+ return index;
}
}
+ if (m->status == JS_MODULE_STATUS_EVALUATING) {
+ *pvalue = JS_UNDEFINED;
+ return index;
+ }
+ assert(m->status == JS_MODULE_STATUS_LINKED);
- m->eval_mark = TRUE;
+ m->status = JS_MODULE_STATUS_EVALUATING;
+ m->dfs_index = index;
+ m->dfs_ancestor_index = index;
+ m->pending_async_dependencies = 0;
+ index++;
+ /* push 'm' on stack */
+ m->stack_prev = *pstack_top;
+ *pstack_top = m;
for(i = 0; i < m->req_module_entries_count; i++) {
JSReqModuleEntry *rme = &m->req_module_entries[i];
m1 = rme->module;
- if (!m1->eval_mark) {
- ret_val = js_evaluate_module(ctx, m1);
- if (JS_IsException(ret_val)) {
- m->eval_mark = FALSE;
- return ret_val;
+ index = js_inner_module_evaluation(ctx, m1, index, pstack_top, pvalue);
+ if (index < 0)
+ return -1;
+ assert(m1->status == JS_MODULE_STATUS_EVALUATING ||
+ m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m1->status == JS_MODULE_STATUS_EVALUATED);
+ if (m1->status == JS_MODULE_STATUS_EVALUATING) {
+ m->dfs_ancestor_index = min_int(m->dfs_ancestor_index,
+ m1->dfs_ancestor_index);
+ } else {
+ m1 = m1->cycle_root;
+ assert(m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m1->status == JS_MODULE_STATUS_EVALUATED);
+ if (m1->eval_has_exception) {
+ *pvalue = JS_DupValue(ctx, m1->eval_exception);
+ return -1;
}
- JS_FreeValue(ctx, ret_val);
+ }
+ if (m1->async_evaluation) {
+ m->pending_async_dependencies++;
+ if (js_resize_array(ctx, (void **)&m1->async_parent_modules, sizeof(m1->async_parent_modules[0]), &m1->async_parent_modules_size, m1->async_parent_modules_count + 1)) {
+ *pvalue = JS_GetException(ctx);
+ return -1;
+ }
+ m1->async_parent_modules[m1->async_parent_modules_count++] = m;
}
}
- if (m->init_func) {
- /* C module init */
- if (m->init_func(ctx, m) < 0)
- ret_val = JS_EXCEPTION;
- else
- ret_val = JS_UNDEFINED;
+ if (m->pending_async_dependencies > 0) {
+ assert(!m->async_evaluation);
+ m->async_evaluation = TRUE;
+ m->async_evaluation_timestamp =
+ ctx->rt->module_async_evaluation_next_timestamp++;
+ } else if (m->has_tla) {
+ assert(!m->async_evaluation);
+ m->async_evaluation = TRUE;
+ m->async_evaluation_timestamp =
+ ctx->rt->module_async_evaluation_next_timestamp++;
+ js_execute_async_module(ctx, m);
} else {
- ret_val = JS_CallFree(ctx, m->func_obj, JS_UNDEFINED, 0, NULL);
- m->func_obj = JS_UNDEFINED;
+ if (js_execute_sync_module(ctx, m, pvalue) < 0)
+ return -1;
}
- if (JS_IsException(ret_val)) {
- /* save the thrown exception value */
- m->eval_has_exception = TRUE;
- m->eval_exception = JS_DupValue(ctx, ctx->rt->current_exception);
+
+ assert(m->dfs_ancestor_index <= m->dfs_index);
+ if (m->dfs_index == m->dfs_ancestor_index) {
+ for(;;) {
+ /* pop m1 from stack */
+ m1 = *pstack_top;
+ *pstack_top = m1->stack_prev;
+ if (!m1->async_evaluation) {
+ m1->status = JS_MODULE_STATUS_EVALUATED;
+ } else {
+ m1->status = JS_MODULE_STATUS_EVALUATING_ASYNC;
+ }
+ /* spec bug: cycle_root must be assigned before the test */
+ m1->cycle_root = m;
+ if (m1 == m)
+ break;
+ }
}
- m->eval_mark = FALSE;
- m->evaluated = TRUE;
- return ret_val;
+ *pvalue = JS_UNDEFINED;
+ return index;
+}
+
+/* Run the <eval> function of the module and of all its requested
+ modules. Return a promise or an exception. */
+static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m)
+{
+ JSModuleDef *m1, *stack_top;
+ JSValue ret_val, result;
+
+ assert(m->status == JS_MODULE_STATUS_LINKED ||
+ m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m->status == JS_MODULE_STATUS_EVALUATED);
+ if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m->status == JS_MODULE_STATUS_EVALUATED) {
+ m = m->cycle_root;
+ }
+ /* a promise may be created only on the cycle_root of a cycle */
+ if (!JS_IsUndefined(m->promise))
+ return JS_DupValue(ctx, m->promise);
+ m->promise = JS_NewPromiseCapability(ctx, m->resolving_funcs);
+ if (JS_IsException(m->promise))
+ return JS_EXCEPTION;
+
+ stack_top = NULL;
+ if (js_inner_module_evaluation(ctx, m, 0, &stack_top, &result) < 0) {
+ while (stack_top != NULL) {
+ m1 = stack_top;
+ assert(m1->status == JS_MODULE_STATUS_EVALUATING);
+ m1->status = JS_MODULE_STATUS_EVALUATED;
+ m1->eval_has_exception = TRUE;
+ m1->eval_exception = JS_DupValue(ctx, result);
+ m1->cycle_root = m; /* spec bug: should be present */
+ stack_top = m1->stack_prev;
+ }
+ JS_FreeValue(ctx, result);
+ assert(m->status == JS_MODULE_STATUS_EVALUATED);
+ assert(m->eval_has_exception);
+ ret_val = JS_Call(ctx, m->resolving_funcs[1], JS_UNDEFINED,
+ 1, (JSValueConst *)&m->eval_exception);
+ JS_FreeValue(ctx, ret_val);
+ } else {
+ assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
+ m->status == JS_MODULE_STATUS_EVALUATED);
+ assert(!m->eval_has_exception);
+ if (!m->async_evaluation) {
+ JSValue value;
+ assert(m->status == JS_MODULE_STATUS_EVALUATED);
+ value = JS_UNDEFINED;
+ ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED,
+ 1, (JSValueConst *)&value);
+ JS_FreeValue(ctx, ret_val);
+ }
+ assert(stack_top == NULL);
+ }
+ return JS_DupValue(ctx, m->promise);
}
-static warn_unused JSAtom js_parse_from_clause(JSParseState *s)
+static __exception JSAtom js_parse_from_clause(JSParseState *s)
{
JSAtom module_name;
if (!token_is_pseudo_keyword(s, JS_ATOM_from)) {
@@ -28446,7 +29217,7 @@ static warn_unused JSAtom js_parse_from_clause(JSParseState *s)
return module_name;
}
-static warn_unused int js_parse_export(JSParseState *s)
+static __exception int js_parse_export(JSParseState *s)
{
JSContext *ctx = s->ctx;
JSModuleDef *m = s->cur_func->module;
@@ -28649,7 +29420,7 @@ static int add_import(JSParseState *s, JSModuleDef *m,
return 0;
}
-static warn_unused int js_parse_import(JSParseState *s)
+static __exception int js_parse_import(JSParseState *s)
{
JSContext *ctx = s->ctx;
JSModuleDef *m = s->cur_func->module;
@@ -28764,7 +29535,7 @@ static warn_unused int js_parse_import(JSParseState *s)
return js_parse_expect_semi(s);
}
-static warn_unused int js_parse_source_element(JSParseState *s)
+static __exception int js_parse_source_element(JSParseState *s)
{
JSFunctionDef *fd = s->cur_func;
int tok;
@@ -29688,7 +30459,8 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
}
var_idx = idx;
break;
- } else if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
+ } else
+ if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
dbuf_putc(bc, OP_get_loc);
dbuf_put_u16(bc, idx);
var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
@@ -29773,6 +30545,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
case OP_scope_get_ref:
dbuf_putc(bc, OP_undefined);
/* fall thru */
+ case OP_scope_get_var_checkthis:
case OP_scope_get_var_undef:
case OP_scope_get_var:
case OP_scope_put_var:
@@ -29798,7 +30571,12 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
}
} else {
if (s->vars[var_idx].is_lexical) {
- dbuf_putc(bc, OP_get_loc_check);
+ if (op == OP_scope_get_var_checkthis) {
+ /* only used for 'this' return in derived class constructors */
+ dbuf_putc(bc, OP_get_loc_checkthis);
+ } else {
+ dbuf_putc(bc, OP_get_loc_check);
+ }
} else {
dbuf_putc(bc, OP_get_loc);
}
@@ -30255,12 +31033,17 @@ static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s,
/* obj func value */
dbuf_putc(bc, OP_call_method);
dbuf_put_u16(bc, 1);
+ dbuf_putc(bc, OP_drop);
}
break;
default:
abort();
}
break;
+ case OP_scope_in_private_field:
+ get_loc_or_ref(bc, is_ref, idx);
+ dbuf_putc(bc, OP_private_in);
+ break;
default:
abort();
}
@@ -30379,12 +31162,13 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
is_arg_scope = (scope_idx == ARG_SCOPE_END);
if (!is_arg_scope) {
/* add unscoped variables */
+ /* XXX: propagate is_const and var_kind too ? */
for(i = 0; i < fd->arg_count; i++) {
vd = &fd->args[i];
if (vd->var_name != JS_ATOM_NULL) {
get_closure_var(ctx, s, fd,
- TRUE, i, vd->var_name, FALSE, FALSE,
- JS_VAR_NORMAL);
+ TRUE, i, vd->var_name, FALSE,
+ vd->is_lexical, JS_VAR_NORMAL);
}
}
for(i = 0; i < fd->var_count; i++) {
@@ -30394,8 +31178,8 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
vd->var_name != JS_ATOM__ret_ &&
vd->var_name != JS_ATOM_NULL) {
get_closure_var(ctx, s, fd,
- FALSE, i, vd->var_name, FALSE, FALSE,
- JS_VAR_NORMAL);
+ FALSE, i, vd->var_name, FALSE,
+ vd->is_lexical, JS_VAR_NORMAL);
}
}
} else {
@@ -30404,8 +31188,8 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
/* do not close top level last result */
if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
get_closure_var(ctx, s, fd,
- FALSE, i, vd->var_name, FALSE, FALSE,
- JS_VAR_NORMAL);
+ FALSE, i, vd->var_name, FALSE,
+ vd->is_lexical, JS_VAR_NORMAL);
}
}
}
@@ -30438,7 +31222,7 @@ static void set_closure_from_var(JSContext *ctx, JSClosureVar *cv,
/* for direct eval compilation: add references to the variables of the
calling function */
-static warn_unused int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
+static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
JSFunctionBytecode *b, int scope_idx)
{
int i, count;
@@ -30858,7 +31642,7 @@ static int get_label_pos(JSFunctionDef *s, int label)
/* convert global variable accesses to local variables or closure
variables when necessary */
-static warn_unused int resolve_variables(JSContext *ctx, JSFunctionDef *s)
+static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
{
int pos, pos_next, bc_len, op, len, i, idx, line_num;
uint8_t *bc_buf;
@@ -30937,6 +31721,7 @@ static warn_unused int resolve_variables(JSContext *ctx, JSFunctionDef *s)
dbuf_putc(&bc_out, op);
dbuf_put_u16(&bc_out, s->scopes[scope].first + 1);
break;
+ case OP_scope_get_var_checkthis:
case OP_scope_get_var_undef:
case OP_scope_get_var:
case OP_scope_put_var:
@@ -30966,6 +31751,7 @@ static warn_unused int resolve_variables(JSContext *ctx, JSFunctionDef *s)
case OP_scope_get_private_field:
case OP_scope_get_private_field2:
case OP_scope_put_private_field:
+ case OP_scope_in_private_field:
{
int ret;
var_name = get_u32(bc_buf + pos + 1);
@@ -31178,6 +31964,17 @@ static warn_unused int resolve_variables(JSContext *ctx, JSFunctionDef *s)
/* only used during parsing */
break;
+ case OP_get_field_opt_chain: /* equivalent to OP_get_field */
+ {
+ JSAtom name = get_u32(bc_buf + pos + 1);
+ dbuf_putc(&bc_out, OP_get_field);
+ dbuf_put_u32(&bc_out, name);
+ }
+ break;
+ case OP_get_array_el_opt_chain: /* equivalent to OP_get_array_el */
+ dbuf_putc(&bc_out, OP_get_array_el);
+ break;
+
default:
no_change:
dbuf_put(&bc_out, bc_buf + pos, len);
@@ -31422,7 +32219,7 @@ static void put_short_code(DynBuf *bc_out, int op, int idx)
}
/* peephole optimizations and resolve goto/labels */
-static warn_unused int resolve_labels(JSContext *ctx, JSFunctionDef *s)
+static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
{
int pos, pos_next, bc_len, op, op1, len, i, line_num;
const uint8_t *bc_buf;
@@ -32231,7 +33028,8 @@ static warn_unused int resolve_labels(JSContext *ctx, JSFunctionDef *s)
bc_out.buf[pos - 1] = jp->op = OP_if_false8 + (op - OP_if_false);
}
goto shrink;
- } else if (diff == (int16_t)diff && op == OP_goto) {
+ } else
+ if (diff == (int16_t)diff && op == OP_goto) {
//put_u16(bc_out.buf + pos, diff);
jp->size = 2;
delta = 2;
@@ -32308,14 +33106,15 @@ typedef struct StackSizeState {
int bc_len;
int stack_len_max;
uint16_t *stack_level_tab;
+ int32_t *catch_pos_tab;
int *pc_stack;
int pc_stack_len;
int pc_stack_size;
} StackSizeState;
/* 'op' is only used for error indication */
-static warn_unused int ss_check(JSContext *ctx, StackSizeState *s,
- int pos, int op, int stack_len)
+static __exception int ss_check(JSContext *ctx, StackSizeState *s,
+ int pos, int op, int stack_len, int catch_pos)
{
if ((unsigned)pos >= s->bc_len) {
JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
@@ -32331,9 +33130,13 @@ static warn_unused int ss_check(JSContext *ctx, StackSizeState *s,
if (s->stack_level_tab[pos] != 0xffff) {
/* already explored: check that the stack size is consistent */
if (s->stack_level_tab[pos] != stack_len) {
- JS_ThrowInternalError(ctx, "unconsistent stack size: %d %d (pc=%d)",
+ JS_ThrowInternalError(ctx, "inconsistent stack size: %d %d (pc=%d)",
s->stack_level_tab[pos], stack_len, pos);
return -1;
+ } else if (s->catch_pos_tab[pos] != catch_pos) {
+ JS_ThrowInternalError(ctx, "inconsistent catch position: %d %d (pc=%d)",
+ s->catch_pos_tab[pos], catch_pos, pos);
+ return -1;
} else {
return 0;
}
@@ -32341,6 +33144,7 @@ static warn_unused int ss_check(JSContext *ctx, StackSizeState *s,
/* mark as explored and store the stack size */
s->stack_level_tab[pos] = stack_len;
+ s->catch_pos_tab[pos] = catch_pos;
/* queue the new PC to explore */
if (js_resize_array(ctx, (void **)&s->pc_stack, sizeof(s->pc_stack[0]),
@@ -32350,12 +33154,12 @@ static warn_unused int ss_check(JSContext *ctx, StackSizeState *s,
return 0;
}
-static warn_unused int compute_stack_size(JSContext *ctx,
+static __exception int compute_stack_size(JSContext *ctx,
JSFunctionDef *fd,
int *pstack_size)
{
StackSizeState s_s, *s = &s_s;
- int i, diff, n_pop, pos_next, stack_len, pos, op;
+ int i, diff, n_pop, pos_next, stack_len, pos, op, catch_pos, catch_level;
const JSOpCode *oi;
const uint8_t *bc_buf;
@@ -32368,24 +33172,33 @@ static warn_unused int compute_stack_size(JSContext *ctx,
return -1;
for(i = 0; i < s->bc_len; i++)
s->stack_level_tab[i] = 0xffff;
- s->stack_len_max = 0;
s->pc_stack = NULL;
+ s->catch_pos_tab = js_malloc(ctx, sizeof(s->catch_pos_tab[0]) *
+ s->bc_len);
+ if (!s->catch_pos_tab)
+ goto fail;
+
+ s->stack_len_max = 0;
s->pc_stack_len = 0;
s->pc_stack_size = 0;
/* breadth-first graph exploration */
- if (ss_check(ctx, s, 0, OP_invalid, 0))
+ if (ss_check(ctx, s, 0, OP_invalid, 0, -1))
goto fail;
while (s->pc_stack_len > 0) {
pos = s->pc_stack[--s->pc_stack_len];
stack_len = s->stack_level_tab[pos];
+ catch_pos = s->catch_pos_tab[pos];
op = bc_buf[pos];
if (op == 0 || op >= OP_COUNT) {
JS_ThrowInternalError(ctx, "invalid opcode (op=%d, pc=%d)", op, pos);
goto fail;
}
oi = &short_opcode_info(op);
+#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 64)
+ printf("%5d: %10s %5d %5d\n", pos, oi->name, stack_len, catch_pos);
+#endif
pos_next = pos + oi->size;
if (pos_next > s->bc_len) {
JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
@@ -32441,55 +33254,104 @@ static warn_unused int compute_stack_size(JSContext *ctx,
case OP_if_true8:
case OP_if_false8:
diff = (int8_t)bc_buf[pos + 1];
- if (ss_check(ctx, s, pos + 1 + diff, op, stack_len))
+ if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
goto fail;
break;
#endif
case OP_if_true:
case OP_if_false:
- case OP_catch:
diff = get_u32(bc_buf + pos + 1);
- if (ss_check(ctx, s, pos + 1 + diff, op, stack_len))
+ if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
goto fail;
break;
case OP_gosub:
diff = get_u32(bc_buf + pos + 1);
- if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1))
+ if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1, catch_pos))
goto fail;
break;
case OP_with_get_var:
case OP_with_delete_var:
diff = get_u32(bc_buf + pos + 5);
- if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1))
+ if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1, catch_pos))
goto fail;
break;
case OP_with_make_ref:
case OP_with_get_ref:
case OP_with_get_ref_undef:
diff = get_u32(bc_buf + pos + 5);
- if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2))
+ if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2, catch_pos))
goto fail;
break;
case OP_with_put_var:
diff = get_u32(bc_buf + pos + 5);
- if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1))
+ if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1, catch_pos))
goto fail;
break;
-
+ case OP_catch:
+ diff = get_u32(bc_buf + pos + 1);
+ if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
+ goto fail;
+ catch_pos = pos;
+ break;
+ case OP_for_of_start:
+ case OP_for_await_of_start:
+ catch_pos = pos;
+ break;
+ /* we assume the catch offset entry is only removed with
+ some op codes */
+ case OP_drop:
+ catch_level = stack_len;
+ goto check_catch;
+ case OP_nip:
+ catch_level = stack_len - 1;
+ goto check_catch;
+ case OP_nip1:
+ catch_level = stack_len - 1;
+ goto check_catch;
+ case OP_iterator_close:
+ catch_level = stack_len + 2;
+ check_catch:
+ /* Note: for for_of_start/for_await_of_start we consider
+ the catch offset is on the first stack entry instead of
+ the thirst */
+ if (catch_pos >= 0) {
+ int level;
+ level = s->stack_level_tab[catch_pos];
+ if (bc_buf[catch_pos] != OP_catch)
+ level++; /* for_of_start, for_wait_of_start */
+ /* catch_level = stack_level before op_catch is executed ? */
+ if (catch_level == level) {
+ catch_pos = s->catch_pos_tab[catch_pos];
+ }
+ }
+ break;
+ case OP_nip_catch:
+ if (catch_pos < 0) {
+ JS_ThrowInternalError(ctx, "nip_catch: no catch op (pc=%d)", pos);
+ goto fail;
+ }
+ stack_len = s->stack_level_tab[catch_pos];
+ if (bc_buf[catch_pos] != OP_catch)
+ stack_len++; /* for_of_start, for_wait_of_start */
+ stack_len++; /* no stack overflow is possible by construction */
+ catch_pos = s->catch_pos_tab[catch_pos];
+ break;
default:
break;
}
- if (ss_check(ctx, s, pos_next, op, stack_len))
+ if (ss_check(ctx, s, pos_next, op, stack_len, catch_pos))
goto fail;
done_insn: ;
}
- js_free(ctx, s->stack_level_tab);
js_free(ctx, s->pc_stack);
+ js_free(ctx, s->catch_pos_tab);
+ js_free(ctx, s->stack_level_tab);
*pstack_size = s->stack_len_max;
return 0;
fail:
- js_free(ctx, s->stack_level_tab);
js_free(ctx, s->pc_stack);
+ js_free(ctx, s->catch_pos_tab);
+ js_free(ctx, s->stack_level_tab);
*pstack_size = 0;
return -1;
}
@@ -32671,10 +33533,8 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
}
} else {
b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
- if (fd->arg_count)
- memcpy(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0]));
- if (fd->var_count)
- memcpy(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0]));
+ memcpy_no_ub(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0]));
+ memcpy_no_ub(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0]));
}
b->var_count = fd->var_count;
b->arg_count = fd->arg_count;
@@ -32736,6 +33596,8 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
b->super_allowed = fd->super_allowed;
b->arguments_allowed = fd->arguments_allowed;
b->backtrace_barrier = fd->backtrace_barrier;
+ b->is_direct_or_indirect_eval = (fd->eval_type == JS_EVAL_TYPE_DIRECT ||
+ fd->eval_type == JS_EVAL_TYPE_INDIRECT);
b->realm = JS_DupContext(ctx);
add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
@@ -32801,7 +33663,7 @@ static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b)
}
}
-static warn_unused int js_parse_directives(JSParseState *s)
+static __exception int js_parse_directives(JSParseState *s)
{
char str[20];
JSParsePos pos;
@@ -32975,7 +33837,7 @@ static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s)
/* func_name must be JS_ATOM_NULL for JS_PARSE_FUNC_STATEMENT and
JS_PARSE_FUNC_EXPR, JS_PARSE_FUNC_ARROW and JS_PARSE_FUNC_VAR */
-static warn_unused int js_parse_function_decl2(JSParseState *s,
+static __exception int js_parse_function_decl2(JSParseState *s,
JSParseFunctionEnum func_type,
JSFunctionKindEnum func_kind,
JSAtom func_name,
@@ -33018,8 +33880,9 @@ static warn_unused int js_parse_function_decl2(JSParseState *s,
func_type == JS_PARSE_FUNC_EXPR &&
(func_kind & JS_FUNC_GENERATOR)) ||
(s->token.u.ident.atom == JS_ATOM_await &&
- func_type == JS_PARSE_FUNC_EXPR &&
- (func_kind & JS_FUNC_ASYNC))) {
+ ((func_type == JS_PARSE_FUNC_EXPR &&
+ (func_kind & JS_FUNC_ASYNC)) ||
+ func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))) {
return js_parse_error_reserved_identifier(s);
}
}
@@ -33113,7 +33976,8 @@ static warn_unused int js_parse_function_decl2(JSParseState *s,
func_type == JS_PARSE_FUNC_SETTER ||
func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||
func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
- fd->has_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW);
+ fd->has_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW &&
+ func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT);
fd->has_this_binding = fd->has_arguments_binding;
fd->is_derived_class_constructor = (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
if (func_type == JS_PARSE_FUNC_ARROW) {
@@ -33121,6 +33985,11 @@ static warn_unused int js_parse_function_decl2(JSParseState *s,
fd->super_call_allowed = fd->parent->super_call_allowed;
fd->super_allowed = fd->parent->super_allowed;
fd->arguments_allowed = fd->parent->arguments_allowed;
+ } else if (func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) {
+ fd->new_target_allowed = TRUE; // although new.target === undefined
+ fd->super_call_allowed = FALSE;
+ fd->super_allowed = TRUE;
+ fd->arguments_allowed = FALSE;
} else {
fd->new_target_allowed = TRUE;
fd->super_call_allowed = fd->is_derived_class_constructor;
@@ -33158,7 +34027,7 @@ static warn_unused int js_parse_function_decl2(JSParseState *s,
if (add_arg(ctx, fd, name) < 0)
goto fail;
fd->defined_arg_count = 1;
- } else {
+ } else if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) {
if (s->token.val == '(') {
int skip_bits;
/* if there is an '=' inside the parameter list, we
@@ -33219,6 +34088,8 @@ static warn_unused int js_parse_function_decl2(JSParseState *s,
goto fail;
}
if (fd->has_parameter_expressions) {
+ if (js_parse_check_duplicate_parameter(s, name))
+ goto fail;
if (define_var(s, fd, name, JS_VAR_DEF_LET) < 0)
goto fail;
}
@@ -33379,8 +34250,10 @@ static warn_unused int js_parse_function_decl2(JSParseState *s,
}
}
- if (js_parse_expect(s, '{'))
- goto fail;
+ if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) {
+ if (js_parse_expect(s, '{'))
+ goto fail;
+ }
if (js_parse_directives(s))
goto fail;
@@ -33410,9 +34283,15 @@ static warn_unused int js_parse_function_decl2(JSParseState *s,
if (js_is_live_code(s)) {
emit_return(s, FALSE);
}
-done:
+ done:
s->cur_func = fd->parent;
+ /* Reparse identifiers after the function is terminated so that
+ the token is parsed in the englobing function. It could be done
+ by just using next_token() here for normal functions, but it is
+ necessary for arrow functions with an expression body. */
+ reparse_ident_token(s);
+
/* create the function object */
{
int idx;
@@ -33523,7 +34402,7 @@ done:
return -1;
}
-static warn_unused int js_parse_function_decl(JSParseState *s,
+static __exception int js_parse_function_decl(JSParseState *s,
JSParseFunctionEnum func_type,
JSFunctionKindEnum func_kind,
JSAtom func_name,
@@ -33535,7 +34414,7 @@ static warn_unused int js_parse_function_decl(JSParseState *s,
NULL);
}
-static warn_unused int js_parse_program(JSParseState *s)
+static __exception int js_parse_program(JSParseState *s)
{
JSFunctionDef *fd = s->cur_func;
int idx;
@@ -33564,12 +34443,24 @@ static warn_unused int js_parse_program(JSParseState *s)
if (!s->is_module) {
/* return the value of the hidden variable eval_ret_idx */
- emit_op(s, OP_get_loc);
- emit_u16(s, fd->eval_ret_idx);
+ if (fd->func_kind == JS_FUNC_ASYNC) {
+ /* wrap the return value in an object so that promises can
+ be safely returned */
+ emit_op(s, OP_object);
+ emit_op(s, OP_dup);
- emit_op(s, OP_return);
+ emit_op(s, OP_get_loc);
+ emit_u16(s, fd->eval_ret_idx);
+
+ emit_op(s, OP_put_field);
+ emit_atom(s, JS_ATOM_value);
+ } else {
+ emit_op(s, OP_get_loc);
+ emit_u16(s, fd->eval_ret_idx);
+ }
+ emit_return(s, TRUE);
} else {
- emit_op(s, OP_return_undef);
+ emit_return(s, FALSE);
}
return 0;
@@ -33612,7 +34503,6 @@ static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj,
ret_val = js_evaluate_module(ctx, m);
if (JS_IsException(ret_val)) {
fail:
- js_free_modules(ctx, JS_FREE_MODULE_NOT_EVALUATED);
return JS_EXCEPTION;
}
} else {
@@ -33627,33 +34517,8 @@ JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj)
return JS_EvalFunctionInternal(ctx, fun_obj, ctx->global_obj, NULL, NULL);
}
-static void skip_shebang(JSParseState *s)
-{
- const uint8_t *p = s->buf_ptr;
- int c;
-
- if (p[0] == '#' && p[1] == '!') {
- p += 2;
- while (p < s->buf_end) {
- if (*p == '\n' || *p == '\r') {
- break;
- } else if (*p >= 0x80) {
- c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
- if (c == CP_LS || c == CP_PS) {
- break;
- } else if (c == -1) {
- p++; /* skip invalid UTF-8 */
- }
- } else {
- p++;
- }
- }
- s->buf_ptr = p;
- }
-}
-
/* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
-static JSValue JS_EvalInternalImpl(JSContext *ctx, JSValueConst this_obj,
+static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
const char *input, size_t input_len,
const char *filename, int line, int flags, int scope_idx)
{
@@ -33667,7 +34532,7 @@ static JSValue JS_EvalInternalImpl(JSContext *ctx, JSValueConst this_obj,
JSModuleDef *m;
js_parse_init(ctx, s, input, input_len, filename, line);
- skip_shebang(s);
+ skip_shebang(&s->buf_ptr, s->buf_end);
eval_type = flags & JS_EVAL_TYPE_MASK;
m = NULL;
@@ -33725,6 +34590,10 @@ static JSValue JS_EvalInternalImpl(JSContext *ctx, JSValueConst this_obj,
goto fail;
}
fd->module = m;
+ if (m != NULL || (flags & JS_EVAL_FLAG_ASYNC)) {
+ fd->in_function_body = TRUE;
+ fd->func_kind = JS_FUNC_ASYNC;
+ }
s->is_module = (m != NULL);
s->allow_html_comments = !s->is_module;
@@ -33739,6 +34608,9 @@ static JSValue JS_EvalInternalImpl(JSContext *ctx, JSValueConst this_obj,
goto fail1;
}
+ if (m != NULL)
+ m->has_tla = fd->has_await;
+
/* create the function object and all the enclosed functions */
fun_obj = js_create_function(ctx, fd);
if (JS_IsException(fun_obj))
@@ -33748,7 +34620,7 @@ static JSValue JS_EvalInternalImpl(JSContext *ctx, JSValueConst this_obj,
m->func_obj = fun_obj;
if (js_resolve_module(ctx, m) < 0)
goto fail1;
- fun_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
+ fun_obj = JS_NewModuleValue(ctx, m);
}
if (flags & JS_EVAL_FLAG_COMPILE_ONLY) {
ret_val = fun_obj;
@@ -33944,8 +34816,6 @@ typedef enum BCTagEnum {
BC_TAG_OBJECT,
BC_TAG_ARRAY,
BC_TAG_BIG_INT,
- BC_TAG_BIG_FLOAT,
- BC_TAG_BIG_DECIMAL,
BC_TAG_TEMPLATE_OBJECT,
BC_TAG_FUNCTION_BYTECODE,
BC_TAG_MODULE,
@@ -33955,24 +34825,21 @@ typedef enum BCTagEnum {
BC_TAG_DATE,
BC_TAG_OBJECT_VALUE,
BC_TAG_OBJECT_REFERENCE,
+#ifdef CONFIG_BIGNUM
+ BC_TAG_BIG_FLOAT,
+ BC_TAG_BIG_DECIMAL,
+#endif
} BCTagEnum;
#ifdef CONFIG_BIGNUM
-#define BC_BASE_VERSION 2
-#else
-#define BC_BASE_VERSION 1
-#endif
-#define BC_BE_VERSION 0x40
-#ifdef WORDS_BIGENDIAN
-#define BC_VERSION (BC_BASE_VERSION | BC_BE_VERSION)
+#define BC_VERSION 0x43
#else
-#define BC_VERSION BC_BASE_VERSION
+#define BC_VERSION 3
#endif
typedef struct BCWriterState {
JSContext *ctx;
DynBuf dbuf;
- BOOL byte_swap : 8;
BOOL allow_bytecode : 8;
BOOL allow_sab : 8;
BOOL allow_reference : 8;
@@ -34002,8 +34869,6 @@ static const char * const bc_tag_str[] = {
"object",
"array",
"bigint",
- "bigfloat",
- "bigdecimal",
"template",
"function",
"module",
@@ -34013,9 +34878,22 @@ static const char * const bc_tag_str[] = {
"Date",
"ObjectValue",
"ObjectReference",
+#ifdef CONFIG_BIGNUM
+ "bigfloat",
+ "bigdecimal",
+#endif
};
#endif
+static inline BOOL is_be(void)
+{
+ union {
+ uint16_t a;
+ uint8_t b;
+ } u = {0x100};
+ return u.b;
+}
+
static void bc_put_u8(BCWriterState *s, uint8_t v)
{
dbuf_putc(&s->dbuf, v);
@@ -34023,21 +34901,21 @@ static void bc_put_u8(BCWriterState *s, uint8_t v)
static void bc_put_u16(BCWriterState *s, uint16_t v)
{
- if (s->byte_swap)
+ if (is_be())
v = bswap16(v);
dbuf_put_u16(&s->dbuf, v);
}
-static maybe_unused void bc_put_u32(BCWriterState *s, uint32_t v)
+static __maybe_unused void bc_put_u32(BCWriterState *s, uint32_t v)
{
- if (s->byte_swap)
+ if (is_be())
v = bswap32(v);
dbuf_put_u32(&s->dbuf, v);
}
static void bc_put_u64(BCWriterState *s, uint64_t v)
{
- if (s->byte_swap)
+ if (is_be())
v = bswap64(v);
dbuf_put(&s->dbuf, (uint8_t *)&v, sizeof(v));
}
@@ -34062,7 +34940,7 @@ static int bc_atom_to_idx(BCWriterState *s, uint32_t *pres, JSAtom atom)
{
uint32_t v;
- if (atom < s->first_atom || JS_AtomIsTaggedInt(atom)) {
+ if (atom < s->first_atom || __JS_AtomIsTaggedInt(atom)) {
*pres = atom;
return 0;
}
@@ -34102,8 +34980,8 @@ static int bc_put_atom(BCWriterState *s, JSAtom atom)
{
uint32_t v;
- if (JS_AtomIsTaggedInt(atom)) {
- v = (JS_AtomToUInt32(atom) << 1) | 1;
+ if (__JS_AtomIsTaggedInt(atom)) {
+ v = (__JS_AtomToUInt32(atom) << 1) | 1;
} else {
if (bc_atom_to_idx(s, &v, atom))
return -1;
@@ -34207,7 +35085,7 @@ static int JS_WriteFunctionBytecode(BCWriterState *s,
pos += len;
}
- if (s->byte_swap)
+ if (is_be())
bc_byte_swap(bc_buf, bc_len);
dbuf_put(&s->dbuf, bc_buf, bc_len);
@@ -34222,7 +35100,7 @@ static int JS_WriteFunctionBytecode(BCWriterState *s,
static void JS_WriteString(BCWriterState *s, JSString *p)
{
int i;
- bc_put_leb128(s, (p->len << 1) | p->is_wide_char);
+ bc_put_leb128(s, ((uint32_t)p->len << 1) | p->is_wide_char);
if (p->is_wide_char) {
for(i = 0; i < p->len; i++)
bc_put_u16(s, p->u.str16[i]);
@@ -34231,7 +35109,6 @@ static void JS_WriteString(BCWriterState *s, JSString *p)
}
}
-#ifdef CONFIG_BIGNUM
static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj)
{
uint32_t tag, tag1;
@@ -34246,12 +35123,14 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj)
case JS_TAG_BIG_INT:
tag1 = BC_TAG_BIG_INT;
break;
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
tag1 = BC_TAG_BIG_FLOAT;
break;
case JS_TAG_BIG_DECIMAL:
tag1 = BC_TAG_BIG_DECIMAL;
break;
+#endif
default:
abort();
}
@@ -34268,7 +35147,7 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj)
e = a->expn + 3;
else
e = a->expn;
- e = (e << 1) | a->sign;
+ e = (e * 2) | a->sign;
if (e < INT32_MIN || e > INT32_MAX) {
JS_ThrowInternalError(s->ctx, "bignum exponent is too large");
return -1;
@@ -34297,20 +35176,14 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj)
bc_put_leb128(s, len);
/* always saved in byte based little endian representation */
for(j = 0; j < n1; j++) {
- dbuf_putc(&s->dbuf, v >> (j * 8));
+ bc_put_u8(s, v >> (j * 8));
}
for(; i < a->len; i++) {
limb_t v = a->tab[i];
#if LIMB_BITS == 32
-#ifdef WORDS_BIGENDIAN
- v = bswap32(v);
-#endif
- dbuf_put_u32(&s->dbuf, v);
+ bc_put_u32(s, v);
#else
-#ifdef WORDS_BIGENDIAN
- v = bswap64(v);
-#endif
- dbuf_put_u64(&s->dbuf, v);
+ bc_put_u64(s, v);
#endif
}
} else {
@@ -34353,20 +35226,19 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj)
v8 = d;
bpos = 1;
} else {
- dbuf_putc(&s->dbuf, v8 | (d << 4));
+ bc_put_u8(s, v8 | (d << 4));
bpos = 0;
}
}
}
/* flush the last digit */
if (bpos) {
- dbuf_putc(&s->dbuf, v8);
+ bc_put_u8(s, v8);
}
}
}
return 0;
}
-#endif /* CONFIG_BIGNUM */
static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj);
@@ -34389,6 +35261,7 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)
bc_set_flags(&flags, &idx, b->arguments_allowed, 1);
bc_set_flags(&flags, &idx, b->has_debug, 1);
bc_set_flags(&flags, &idx, b->backtrace_barrier, 1);
+ bc_set_flags(&flags, &idx, b->is_direct_or_indirect_eval, 1);
assert(idx <= 16);
bc_put_u16(s, flags);
bc_put_u8(s, b->js_mode);
@@ -34495,6 +35368,8 @@ static int JS_WriteModule(BCWriterState *s, JSValueConst obj)
bc_put_leb128(s, mi->req_module_idx);
}
+ bc_put_u8(s, m->has_tla);
+
if (JS_WriteObjectRec(s, m->func_obj))
goto fail;
return 0;
@@ -34723,8 +35598,8 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj)
case JS_CLASS_NUMBER:
case JS_CLASS_STRING:
case JS_CLASS_BOOLEAN:
-#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT:
+#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_FLOAT:
case JS_CLASS_BIG_DECIMAL:
#endif
@@ -34746,14 +35621,14 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj)
goto fail;
}
break;
-#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
case JS_TAG_BIG_DECIMAL:
+#endif
if (JS_WriteBigNum(s, obj))
goto fail;
break;
-#endif
default:
invalid_tag:
JS_ThrowInternalError(s->ctx, "unsupported tag (%d)", tag);
@@ -34771,15 +35646,10 @@ static int JS_WriteObjectAtoms(BCWriterState *s)
JSRuntime *rt = s->ctx->rt;
DynBuf dbuf1;
int i, atoms_size;
- uint8_t version;
dbuf1 = s->dbuf;
js_dbuf_init(s->ctx, &s->dbuf);
-
- version = BC_VERSION;
- if (s->byte_swap)
- version ^= BC_BE_VERSION;
- bc_put_u8(s, version);
+ bc_put_u8(s, BC_VERSION);
bc_put_leb128(s, s->idx_to_atom_count);
for(i = 0; i < s->idx_to_atom_count; i++) {
@@ -34812,8 +35682,6 @@ uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,
memset(s, 0, sizeof(*s));
s->ctx = ctx;
- /* XXX: byte swapped output is untested */
- s->byte_swap = ((flags & JS_WRITE_OBJ_BSWAP) != 0);
s->allow_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0);
s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0);
s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 0);
@@ -34934,33 +35802,45 @@ static int bc_get_u8(BCReaderState *s, uint8_t *pval)
static int bc_get_u16(BCReaderState *s, uint16_t *pval)
{
+ uint16_t v;
if (unlikely(s->buf_end - s->ptr < 2)) {
*pval = 0; /* avoid warning */
return bc_read_error_end(s);
}
- *pval = get_u16(s->ptr);
+ v = get_u16(s->ptr);
+ if (is_be())
+ v = bswap16(v);
+ *pval = v;
s->ptr += 2;
return 0;
}
-static maybe_unused int bc_get_u32(BCReaderState *s, uint32_t *pval)
+static __maybe_unused int bc_get_u32(BCReaderState *s, uint32_t *pval)
{
+ uint32_t v;
if (unlikely(s->buf_end - s->ptr < 4)) {
*pval = 0; /* avoid warning */
return bc_read_error_end(s);
}
- *pval = get_u32(s->ptr);
+ v = get_u32(s->ptr);
+ if (is_be())
+ v = bswap32(v);
+ *pval = v;
s->ptr += 4;
return 0;
}
static int bc_get_u64(BCReaderState *s, uint64_t *pval)
{
+ uint64_t v;
if (unlikely(s->buf_end - s->ptr < 8)) {
*pval = 0; /* avoid warning */
return bc_read_error_end(s);
}
- *pval = get_u64(s->ptr);
+ v = get_u64(s->ptr);
+ if (is_be())
+ v = bswap64(v);
+ *pval = v;
s->ptr += 8;
return 0;
}
@@ -35017,7 +35897,7 @@ static int bc_idx_to_atom(BCReaderState *s, JSAtom *patom, uint32_t idx)
{
JSAtom atom;
- if (JS_AtomIsTaggedInt(idx)) {
+ if (__JS_AtomIsTaggedInt(idx)) {
atom = idx;
} else if (idx < s->first_atom) {
atom = JS_DupAtom(s->ctx, idx);
@@ -35041,7 +35921,7 @@ static int bc_get_atom(BCReaderState *s, JSAtom *patom)
if (bc_get_leb128(s, &v))
return -1;
if (v & 1) {
- *patom = JS_AtomFromUInt32(v >> 1);
+ *patom = __JS_AtomFromUInt32(v >> 1);
return 0;
} else {
return bc_idx_to_atom(s, patom, v >> 1);
@@ -35072,7 +35952,13 @@ static JSString *JS_ReadString(BCReaderState *s)
}
memcpy(p->u.str8, s->ptr, size);
s->ptr += size;
- if (!is_wide_char) {
+ if (is_wide_char) {
+ if (is_be()) {
+ uint32_t i;
+ for (i = 0; i < len; i++)
+ p->u.str16[i] = bswap16(p->u.str16[i]);
+ }
+ } else {
p->u.str8[size] = '\0'; /* add the trailing zero for 8 bit strings */
}
#ifdef DUMP_READ_OBJECT
@@ -35111,6 +35997,9 @@ static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b,
}
b->byte_code_buf = bc_buf;
+ if (is_be())
+ bc_byte_swap(bc_buf, bc_len);
+
pos = 0;
while (pos < bc_len) {
op = bc_buf[pos];
@@ -35145,18 +36034,16 @@ static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b,
return 0;
}
-#ifdef CONFIG_BIGNUM
static JSValue JS_ReadBigNum(BCReaderState *s, int tag)
{
JSValue obj = JS_UNDEFINED;
uint8_t v8;
int32_t e;
uint32_t len;
- limb_t l, i, n, j;
+ limb_t l, i, n;
JSBigFloat *p;
limb_t v;
bf_t *a;
- int bpos, d;
p = js_new_bf(s->ctx);
if (!p)
@@ -35165,12 +36052,14 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag)
case BC_TAG_BIG_INT:
obj = JS_MKPTR(JS_TAG_BIG_INT, p);
break;
+#ifdef CONFIG_BIGNUM
case BC_TAG_BIG_FLOAT:
obj = JS_MKPTR(JS_TAG_BIG_FLOAT, p);
break;
case BC_TAG_BIG_DECIMAL:
obj = JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
break;
+#endif
default:
abort();
}
@@ -35204,45 +36093,23 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag)
JS_ThrowInternalError(s->ctx, "invalid bignum length");
goto fail;
}
- if (tag != BC_TAG_BIG_DECIMAL)
- l = (len + sizeof(limb_t) - 1) / sizeof(limb_t);
- else
+#ifdef CONFIG_BIGNUM
+ if (tag == BC_TAG_BIG_DECIMAL) {
l = (len + LIMB_DIGITS - 1) / LIMB_DIGITS;
+ } else
+#endif
+ {
+ l = (len + sizeof(limb_t) - 1) / sizeof(limb_t);
+ }
if (bf_resize(a, l)) {
JS_ThrowOutOfMemory(s->ctx);
goto fail;
}
- if (tag != BC_TAG_BIG_DECIMAL) {
- n = len & (sizeof(limb_t) - 1);
- if (n != 0) {
- v = 0;
- for(i = 0; i < n; i++) {
- if (bc_get_u8(s, &v8))
- goto fail;
- v |= (limb_t)v8 << ((sizeof(limb_t) - n + i) * 8);
- }
- a->tab[0] = v;
- i = 1;
- } else {
- i = 0;
- }
- for(; i < l; i++) {
-#if LIMB_BITS == 32
- if (bc_get_u32(s, &v))
- goto fail;
-#ifdef WORDS_BIGENDIAN
- v = bswap32(v);
-#endif
-#else
- if (bc_get_u64(s, &v))
- goto fail;
-#ifdef WORDS_BIGENDIAN
- v = bswap64(v);
-#endif
-#endif
- a->tab[i] = v;
- }
- } else {
+#ifdef CONFIG_BIGNUM
+ if (tag == BC_TAG_BIG_DECIMAL) {
+ limb_t j;
+ int bpos, d;
+
bpos = 0;
for(i = 0; i < l; i++) {
if (i == 0 && (n = len % LIMB_DIGITS) != 0) {
@@ -35269,6 +36136,32 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag)
}
a->tab[i] = v;
}
+ } else
+#endif /* CONFIG_BIGNUM */
+ {
+ n = len & (sizeof(limb_t) - 1);
+ if (n != 0) {
+ v = 0;
+ for(i = 0; i < n; i++) {
+ if (bc_get_u8(s, &v8))
+ goto fail;
+ v |= (limb_t)v8 << ((sizeof(limb_t) - n + i) * 8);
+ }
+ a->tab[0] = v;
+ i = 1;
+ } else {
+ i = 0;
+ }
+ for(; i < l; i++) {
+#if LIMB_BITS == 32
+ if (bc_get_u32(s, &v))
+ goto fail;
+#else
+ if (bc_get_u64(s, &v))
+ goto fail;
+#endif
+ a->tab[i] = v;
+ }
}
}
bc_read_trace(s, "}\n");
@@ -35277,7 +36170,6 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag)
JS_FreeValue(s->ctx, obj);
return JS_EXCEPTION;
}
-#endif /* CONFIG_BIGNUM */
static JSValue JS_ReadObjectRec(BCReaderState *s);
@@ -35327,6 +36219,7 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
bc.arguments_allowed = bc_get_flags(v16, &idx, 1);
bc.has_debug = bc_get_flags(v16, &idx, 1);
bc.backtrace_barrier = bc_get_flags(v16, &idx, 1);
+ bc.is_direct_or_indirect_eval = bc_get_flags(v16, &idx, 1);
bc.read_only_bytecode = s->is_rom_data;
if (bc_get_u8(s, &v8))
goto fail;
@@ -35505,7 +36398,7 @@ static JSValue JS_ReadModule(BCReaderState *s)
m = js_new_module_def(ctx, module_name);
if (!m)
goto fail;
- obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
+ obj = JS_NewModuleValue(ctx, m);
if (bc_get_leb128_int(s, &m->req_module_entries_count))
goto fail;
if (m->req_module_entries_count != 0) {
@@ -35578,6 +36471,10 @@ static JSValue JS_ReadModule(BCReaderState *s)
}
}
+ if (bc_get_u8(s, &v8))
+ goto fail;
+ m->has_tla = (v8 != 0);
+
m->func_obj = JS_ReadObjectRec(s);
if (JS_IsException(m->func_obj))
goto fail;
@@ -35856,7 +36753,7 @@ static JSValue JS_ReadObjectRec(BCReaderState *s)
if (bc_get_u64(s, &u.u64))
return JS_EXCEPTION;
bc_read_trace(s, "%g\n", u.d);
- obj = JS_NewFloat64Impl(ctx, u.d);
+ obj = __JS_NewFloat64(ctx, u.d);
}
break;
case BC_TAG_STRING:
@@ -35902,13 +36799,13 @@ static JSValue JS_ReadObjectRec(BCReaderState *s)
case BC_TAG_OBJECT_VALUE:
obj = JS_ReadObjectValue(s);
break;
-#ifdef CONFIG_BIGNUM
case BC_TAG_BIG_INT:
+#ifdef CONFIG_BIGNUM
case BC_TAG_BIG_FLOAT:
case BC_TAG_BIG_DECIMAL:
+#endif
obj = JS_ReadBigNum(s, tag);
break;
-#endif
case BC_TAG_OBJECT_REFERENCE:
{
uint32_t val;
@@ -35942,7 +36839,6 @@ static int JS_ReadObjectAtoms(BCReaderState *s)
if (bc_get_u8(s, &v8))
return -1;
- /* XXX: could support byte swapped input */
if (v8 != BC_VERSION) {
JS_ThrowSyntaxError(s->ctx, "invalid version (%d expected=%d)",
v8, BC_VERSION);
@@ -36164,7 +37060,7 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj,
val = JS_NewInt64(ctx, e->u.i64);
break;
case JS_DEF_PROP_DOUBLE:
- val = JS_NewFloat64Impl(ctx, e->u.f64);
+ val = __JS_NewFloat64(ctx, e->u.f64);
break;
case JS_DEF_PROP_UNDEFINED:
val = JS_UNDEFINED;
@@ -36228,7 +37124,7 @@ int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
val = JS_NewInt64(ctx, e->u.i64);
break;
case JS_DEF_PROP_DOUBLE:
- val = JS_NewFloat64Impl(ctx, e->u.f64);
+ val = __JS_NewFloat64(ctx, e->u.f64);
break;
case JS_DEF_OBJECT:
val = JS_NewObject(ctx);
@@ -36317,12 +37213,10 @@ static JSValue js_global_isNaN(JSContext *ctx, JSValueConst this_val,
static JSValue js_global_isFinite(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
- BOOL res;
double d;
if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
return JS_EXCEPTION;
- res = isfinite(d);
- return JS_NewBool(ctx, res);
+ return JS_NewBool(ctx, isfinite(d));
}
/* Object class */
@@ -36340,10 +37234,10 @@ static JSValue JS_ToObject(JSContext *ctx, JSValueConst val)
case JS_TAG_OBJECT:
case JS_TAG_EXCEPTION:
return JS_DupValue(ctx, val);
-#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);
goto set_value;
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_FLOAT);
goto set_value;
@@ -36461,7 +37355,7 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
return -1;
}
-static warn_unused int JS_DefinePropertyDesc(JSContext *ctx, JSValueConst obj,
+static __exception int JS_DefinePropertyDesc(JSContext *ctx, JSValueConst obj,
JSAtom prop, JSValueConst desc,
int flags)
{
@@ -36477,7 +37371,7 @@ static warn_unused int JS_DefinePropertyDesc(JSContext *ctx, JSValueConst obj,
return ret;
}
-static warn_unused int JS_ObjectDefineProperties(JSContext *ctx,
+static __exception int JS_ObjectDefineProperties(JSContext *ctx,
JSValueConst obj,
JSValueConst properties)
{
@@ -36716,13 +37610,13 @@ static JSValue js_object_getOwnPropertyDescriptor(JSContext *ctx, JSValueConst t
} else {
if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, desc.value), flags) < 0
|| JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
- JS_NewBool(ctx, (desc.flags & JS_PROP_WRITABLE) != 0), flags) < 0)
+ JS_NewBool(ctx, desc.flags & JS_PROP_WRITABLE), flags) < 0)
goto exception1;
}
if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
- JS_NewBool(ctx, (desc.flags & JS_PROP_ENUMERABLE) != 0), flags) < 0
+ JS_NewBool(ctx, desc.flags & JS_PROP_ENUMERABLE), flags) < 0
|| JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
- JS_NewBool(ctx, (desc.flags & JS_PROP_CONFIGURABLE) != 0), flags) < 0)
+ JS_NewBool(ctx, desc.flags & JS_PROP_CONFIGURABLE), flags) < 0)
goto exception1;
js_free_desc(ctx, &desc);
}
@@ -36962,6 +37856,32 @@ static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val,
return JS_NewBool(ctx, ret);
}
+static JSValue js_object_hasOwn(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue obj;
+ JSAtom atom;
+ JSObject *p;
+ BOOL ret;
+
+ obj = JS_ToObject(ctx, argv[0]);
+ if (JS_IsException(obj))
+ return obj;
+ atom = JS_ValueToAtom(ctx, argv[1]);
+ if (unlikely(atom == JS_ATOM_NULL)) {
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+ }
+ p = JS_VALUE_GET_OBJ(obj);
+ ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
+ JS_FreeAtom(ctx, atom);
+ JS_FreeValue(ctx, obj);
+ if (ret < 0)
+ return JS_EXCEPTION;
+ else
+ return JS_NewBool(ctx, ret);
+}
+
static JSValue js_object_valueOf(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
@@ -37154,6 +38074,13 @@ exception:
return JS_EXCEPTION;
}
+JSValue JS_ObjectSeal(JSContext *ctx, JSValueConst obj, int freeze)
+{
+ JSValueConst argv[] = {obj};
+ JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, argv, freeze));
+ return obj;
+}
+
static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
@@ -37444,7 +38371,7 @@ static JSValue js_object_propertyIsEnumerable(JSContext *ctx, JSValueConst this_
if (has_prop < 0)
goto exception;
if (has_prop) {
- res = JS_NewBool(ctx, (desc.flags & JS_PROP_ENUMERABLE) != 0);
+ res = JS_NewBool(ctx, desc.flags & JS_PROP_ENUMERABLE);
js_free_desc(ctx, &desc);
} else {
res = JS_FALSE;
@@ -37501,32 +38428,6 @@ exception:
return res;
}
-static JSValue js_object_hasOwn(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
-{
- JSValue obj;
- JSAtom atom;
- JSObject *p;
- BOOL ret;
-
- obj = JS_ToObject(ctx, argv[0]);
- if (JS_IsException(obj))
- return obj;
- atom = JS_ValueToAtom(ctx, argv[1]);
- if (unlikely(atom == JS_ATOM_NULL)) {
- JS_FreeValue(ctx, obj);
- return JS_EXCEPTION;
- }
- p = JS_VALUE_GET_OBJ(obj);
- ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
- JS_FreeAtom(ctx, atom);
- JS_FreeValue(ctx, obj);
- if (ret < 0)
- return JS_EXCEPTION;
- else
- return JS_NewBool(ctx, ret);
-}
-
static const JSCFunctionListEntry js_object_funcs[] = {
JS_CFUNC_DEF("create", 2, js_object_create ),
JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 0 ),
@@ -37535,6 +38436,7 @@ static const JSCFunctionListEntry js_object_funcs[] = {
JS_CFUNC_DEF("defineProperties", 2, js_object_defineProperties ),
JS_CFUNC_DEF("getOwnPropertyNames", 1, js_object_getOwnPropertyNames ),
JS_CFUNC_DEF("getOwnPropertySymbols", 1, js_object_getOwnPropertySymbols ),
+ JS_CFUNC_MAGIC_DEF("groupBy", 2, js_object_groupBy, 0 ),
JS_CFUNC_MAGIC_DEF("keys", 1, js_object_keys, JS_ITERATOR_KIND_KEY ),
JS_CFUNC_MAGIC_DEF("values", 1, js_object_keys, JS_ITERATOR_KIND_VALUE ),
JS_CFUNC_MAGIC_DEF("entries", 1, js_object_keys, JS_ITERATOR_KIND_KEY_AND_VALUE ),
@@ -37656,7 +38558,7 @@ static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target,
return JS_EXCEPTION;
}
-static warn_unused int js_get_length32(JSContext *ctx, uint32_t *pres,
+static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
JSValueConst obj)
{
JSValue len_val;
@@ -37668,7 +38570,7 @@ static warn_unused int js_get_length32(JSContext *ctx, uint32_t *pres,
return JS_ToUint32Free(ctx, pres, len_val);
}
-static warn_unused int js_get_length64(JSContext *ctx, int64_t *pres,
+static __exception int js_get_length64(JSContext *ctx, int64_t *pres,
JSValueConst obj)
{
JSValue len_val;
@@ -37704,7 +38606,9 @@ static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
if (js_get_length32(ctx, &len, array_arg))
return NULL;
if (len > JS_MAX_LOCAL_VARS) {
- JS_ThrowInternalError(ctx, "too many arguments");
+ // XXX: check for stack overflow?
+ JS_ThrowRangeError(ctx, "too many arguments in function call (only %d allowed)",
+ JS_MAX_LOCAL_VARS);
return NULL;
}
/* avoid allocating 0 bytes */
@@ -37753,9 +38657,9 @@ static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
if (!tab)
return JS_EXCEPTION;
if (magic & 1) {
- ret = JS_CallConstructor2(ctx, this_val, this_arg, len, tab);
+ ret = JS_CallConstructor2(ctx, this_val, this_arg, len, (JSValueConst *)tab);
} else {
- ret = JS_Call(ctx, this_val, this_arg, len, tab);
+ ret = JS_Call(ctx, this_val, this_arg, len, (JSValueConst *)tab);
}
free_arg_list(ctx, tab, len);
return ret;
@@ -37965,7 +38869,8 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
int argc, JSValueConst *argv, int magic)
{
JSValue obj, msg, proto;
- JSValueConst message;
+ JSValueConst message, options;
+ int arg_index;
if (JS_IsUndefined(new_target))
new_target = JS_GetActiveFunction(ctx);
@@ -37991,12 +38896,9 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
JS_FreeValue(ctx, proto);
if (JS_IsException(obj))
return obj;
- if (magic == JS_AGGREGATE_ERROR) {
- message = argv[1];
- } else {
- message = argv[0];
- }
+ arg_index = (magic == JS_AGGREGATE_ERROR);
+ message = argv[arg_index++];
if (!JS_IsUndefined(message)) {
msg = JS_ToString(ctx, message);
if (unlikely(JS_IsException(msg)))
@@ -38005,6 +38907,22 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
}
+ if (arg_index < argc) {
+ options = argv[arg_index];
+ if (JS_IsObject(options)) {
+ int present = JS_HasProperty(ctx, options, JS_ATOM_cause);
+ if (present < 0)
+ goto exception;
+ if (present) {
+ JSValue cause = JS_GetProperty(ctx, options, JS_ATOM_cause);
+ if (JS_IsException(cause))
+ goto exception;
+ JS_DefinePropertyValue(ctx, obj, JS_ATOM_cause, cause,
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+ }
+ }
+ }
+
if (magic == JS_AGGREGATE_ERROR) {
JSValue error_list = iterator_to_array(ctx, argv[0]);
if (JS_IsException(error_list))
@@ -38398,6 +39316,106 @@ static int JS_isConcatSpreadable(JSContext *ctx, JSValueConst obj)
return JS_IsArray(ctx, obj);
}
+static JSValue js_array_at(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue obj, ret;
+ int64_t len, idx;
+ JSValue *arrp;
+ uint32_t count;
+
+ obj = JS_ToObject(ctx, this_val);
+ if (js_get_length64(ctx, &len, obj))
+ goto exception;
+
+ if (JS_ToInt64Sat(ctx, &idx, argv[0]))
+ goto exception;
+
+ if (idx < 0)
+ idx = len + idx;
+ if (idx < 0 || idx >= len) {
+ ret = JS_UNDEFINED;
+ } else if (js_get_fast_array(ctx, obj, &arrp, &count) && idx < count) {
+ ret = JS_DupValue(ctx, arrp[idx]);
+ } else {
+ int present = JS_TryGetPropertyInt64(ctx, obj, idx, &ret);
+ if (present < 0)
+ goto exception;
+ if (!present)
+ ret = JS_UNDEFINED;
+ }
+ JS_FreeValue(ctx, obj);
+ return ret;
+ exception:
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+}
+
+static JSValue js_array_with(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue arr, obj, ret, *arrp, *pval;
+ JSObject *p;
+ int64_t i, len, idx;
+ uint32_t count32;
+
+ ret = JS_EXCEPTION;
+ arr = JS_UNDEFINED;
+ obj = JS_ToObject(ctx, this_val);
+ if (js_get_length64(ctx, &len, obj))
+ goto exception;
+
+ if (JS_ToInt64Sat(ctx, &idx, argv[0]))
+ goto exception;
+
+ if (idx < 0)
+ idx = len + idx;
+
+ if (idx < 0 || idx >= len) {
+ JS_ThrowRangeError(ctx, "invalid array index: %" PRId64, idx);
+ goto exception;
+ }
+
+ arr = js_allocate_fast_array(ctx, len);
+ if (JS_IsException(arr))
+ goto exception;
+
+ p = JS_VALUE_GET_OBJ(arr);
+ i = 0;
+ pval = p->u.array.u.values;
+ if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
+ for (; i < idx; i++, pval++)
+ *pval = JS_DupValue(ctx, arrp[i]);
+ *pval = JS_DupValue(ctx, argv[1]);
+ for (i++, pval++; i < len; i++, pval++)
+ *pval = JS_DupValue(ctx, arrp[i]);
+ } else {
+ for (; i < idx; i++, pval++)
+ if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
+ goto fill_and_fail;
+ *pval = JS_DupValue(ctx, argv[1]);
+ for (i++, pval++; i < len; i++, pval++) {
+ if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) {
+ fill_and_fail:
+ for (; i < len; i++, pval++)
+ *pval = JS_UNDEFINED;
+ goto exception;
+ }
+ }
+ }
+
+ if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0)
+ goto exception;
+
+ ret = arr;
+ arr = JS_UNDEFINED;
+
+exception:
+ JS_FreeValue(ctx, arr);
+ JS_FreeValue(ctx, obj);
+ return ret;
+}
+
static JSValue js_array_concat(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
@@ -38763,9 +39781,10 @@ static JSValue js_array_includes(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSValue obj, val;
- int64_t len, n, res;
+ int64_t len, n;
JSValue *arrp;
uint32_t count;
+ int res;
obj = JS_ToObject(ctx, this_val);
if (js_get_length64(ctx, &len, obj))
@@ -38896,13 +39915,21 @@ static JSValue js_array_lastIndexOf(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
}
+enum {
+ ArrayFind,
+ ArrayFindIndex,
+ ArrayFindLast,
+ ArrayFindLastIndex,
+};
+
static JSValue js_array_find(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int findIndex)
+ int argc, JSValueConst *argv, int mode)
{
JSValueConst func, this_arg;
JSValueConst args[3];
JSValue obj, val, index_val, res;
- int64_t len, k;
+ int64_t len, k, end;
+ int dir;
index_val = JS_UNDEFINED;
val = JS_UNDEFINED;
@@ -38918,7 +39945,17 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val,
if (argc > 1)
this_arg = argv[1];
- for(k = 0; k < len; k++) {
+ k = 0;
+ dir = 1;
+ end = len;
+ if (mode == ArrayFindLast || mode == ArrayFindLastIndex) {
+ k = len - 1;
+ dir = -1;
+ end = -1;
+ }
+
+ // TODO(bnoordhuis) add fast path for fast arrays
+ for(; k != end; k += dir) {
index_val = JS_NewInt64(ctx, k);
if (JS_IsException(index_val))
goto exception;
@@ -38932,7 +39969,7 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val,
if (JS_IsException(res))
goto exception;
if (JS_ToBoolFree(ctx, res)) {
- if (findIndex) {
+ if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) {
JS_FreeValue(ctx, val);
JS_FreeValue(ctx, obj);
return index_val;
@@ -38946,7 +39983,7 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val,
JS_FreeValue(ctx, index_val);
}
JS_FreeValue(ctx, obj);
- if (findIndex)
+ if (mode == ArrayFindIndex || mode == ArrayFindLastIndex)
return JS_NewInt32(ctx, -1);
else
return JS_UNDEFINED;
@@ -38969,7 +40006,8 @@ static JSValue js_array_toString(JSContext *ctx, JSValueConst this_val,
method = JS_GetProperty(ctx, obj, JS_ATOM_join);
if (JS_IsException(method)) {
ret = JS_EXCEPTION;
- } else if (!JS_IsFunction(ctx, method)) {
+ } else
+ if (!JS_IsFunction(ctx, method)) {
/* Use intrinsic Object.prototype.toString */
JS_FreeValue(ctx, method);
ret = js_object_toString(ctx, obj, 0, NULL);
@@ -39196,6 +40234,61 @@ static JSValue js_array_reverse(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
}
+// Note: a.toReversed() is a.slice().reverse() with the twist that a.slice()
+// leaves holes in sparse arrays intact whereas a.toReversed() replaces them
+// with undefined, thus in effect creating a dense array.
+// Does not use Array[@@species], always returns a base Array.
+static JSValue js_array_toReversed(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue arr, obj, ret, *arrp, *pval;
+ JSObject *p;
+ int64_t i, len;
+ uint32_t count32;
+
+ ret = JS_EXCEPTION;
+ arr = JS_UNDEFINED;
+ obj = JS_ToObject(ctx, this_val);
+ if (js_get_length64(ctx, &len, obj))
+ goto exception;
+
+ arr = js_allocate_fast_array(ctx, len);
+ if (JS_IsException(arr))
+ goto exception;
+
+ if (len > 0) {
+ p = JS_VALUE_GET_OBJ(arr);
+
+ i = len - 1;
+ pval = p->u.array.u.values;
+ if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
+ for (; i >= 0; i--, pval++)
+ *pval = JS_DupValue(ctx, arrp[i]);
+ } else {
+ // Query order is observable; test262 expects descending order.
+ for (; i >= 0; i--, pval++) {
+ if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) {
+ // Exception; initialize remaining elements.
+ for (; i >= 0; i--, pval++)
+ *pval = JS_UNDEFINED;
+ goto exception;
+ }
+ }
+ }
+
+ if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0)
+ goto exception;
+ }
+
+ ret = arr;
+ arr = JS_UNDEFINED;
+
+exception:
+ JS_FreeValue(ctx, arr);
+ JS_FreeValue(ctx, obj);
+ return ret;
+}
+
static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int splice)
{
@@ -39217,7 +40310,8 @@ static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val,
if (argc == 0) {
item_count = 0;
del_count = 0;
- } else if (argc == 1) {
+ } else
+ if (argc == 1) {
item_count = 0;
del_count = len - start;
} else {
@@ -39302,6 +40396,92 @@ static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
}
+static JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue arr, obj, ret, *arrp, *pval, *last;
+ JSObject *p;
+ int64_t i, j, len, newlen, start, add, del;
+ uint32_t count32;
+
+ pval = NULL;
+ last = NULL;
+ ret = JS_EXCEPTION;
+ arr = JS_UNDEFINED;
+
+ obj = JS_ToObject(ctx, this_val);
+ if (js_get_length64(ctx, &len, obj))
+ goto exception;
+
+ start = 0;
+ if (argc > 0)
+ if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
+ goto exception;
+
+ del = 0;
+ if (argc > 0)
+ del = len - start;
+ if (argc > 1)
+ if (JS_ToInt64Clamp(ctx, &del, argv[1], 0, del, 0))
+ goto exception;
+
+ add = 0;
+ if (argc > 2)
+ add = argc - 2;
+
+ newlen = len + add - del;
+ if (newlen > MAX_SAFE_INTEGER) {
+ JS_ThrowTypeError(ctx, "invalid array length");
+ goto exception;
+ }
+
+ arr = js_allocate_fast_array(ctx, newlen);
+ if (JS_IsException(arr))
+ goto exception;
+
+ if (newlen <= 0)
+ goto done;
+
+ p = JS_VALUE_GET_OBJ(arr);
+ pval = &p->u.array.u.values[0];
+ last = &p->u.array.u.values[newlen];
+
+ if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
+ for (i = 0; i < start; i++, pval++)
+ *pval = JS_DupValue(ctx, arrp[i]);
+ for (j = 0; j < add; j++, pval++)
+ *pval = JS_DupValue(ctx, argv[2 + j]);
+ for (i += del; i < len; i++, pval++)
+ *pval = JS_DupValue(ctx, arrp[i]);
+ } else {
+ for (i = 0; i < start; i++, pval++)
+ if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
+ goto exception;
+ for (j = 0; j < add; j++, pval++)
+ *pval = JS_DupValue(ctx, argv[2 + j]);
+ for (i += del; i < len; i++, pval++)
+ if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
+ goto exception;
+ }
+
+ assert(pval == last);
+
+ if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, newlen)) < 0)
+ goto exception;
+
+done:
+ ret = arr;
+ arr = JS_UNDEFINED;
+
+exception:
+ while (pval != last)
+ *pval++ = JS_UNDEFINED;
+
+ JS_FreeValue(ctx, arr);
+ JS_FreeValue(ctx, obj);
+ return ret;
+}
+
static JSValue js_array_copyWithin(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
@@ -39605,6 +40785,68 @@ fail:
return JS_EXCEPTION;
}
+// Note: a.toSorted() is a.slice().sort() with the twist that a.slice()
+// leaves holes in sparse arrays intact whereas a.toSorted() replaces them
+// with undefined, thus in effect creating a dense array.
+// Does not use Array[@@species], always returns a base Array.
+static JSValue js_array_toSorted(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue arr, obj, ret, *arrp, *pval;
+ JSObject *p;
+ int64_t i, len;
+ uint32_t count32;
+ int ok;
+
+ ok = JS_IsUndefined(argv[0]) || JS_IsFunction(ctx, argv[0]);
+ if (!ok)
+ return JS_ThrowTypeError(ctx, "not a function");
+
+ ret = JS_EXCEPTION;
+ arr = JS_UNDEFINED;
+ obj = JS_ToObject(ctx, this_val);
+ if (js_get_length64(ctx, &len, obj))
+ goto exception;
+
+ arr = js_allocate_fast_array(ctx, len);
+ if (JS_IsException(arr))
+ goto exception;
+
+ if (len > 0) {
+ p = JS_VALUE_GET_OBJ(arr);
+ i = 0;
+ pval = p->u.array.u.values;
+ if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
+ for (; i < len; i++, pval++)
+ *pval = JS_DupValue(ctx, arrp[i]);
+ } else {
+ for (; i < len; i++, pval++) {
+ if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) {
+ for (; i < len; i++, pval++)
+ *pval = JS_UNDEFINED;
+ goto exception;
+ }
+ }
+ }
+
+ if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0)
+ goto exception;
+ }
+
+ ret = js_array_sort(ctx, arr, argc, argv);
+ if (JS_IsException(ret))
+ goto exception;
+ JS_FreeValue(ctx, ret);
+
+ ret = arr;
+ arr = JS_UNDEFINED;
+
+exception:
+ JS_FreeValue(ctx, arr);
+ JS_FreeValue(ctx, obj);
+ return ret;
+}
+
typedef struct JSArrayIteratorData {
JSValue obj;
JSIteratorKindEnum kind;
@@ -39757,6 +40999,8 @@ static const JSCFunctionListEntry js_iterator_proto_funcs[] = {
};
static const JSCFunctionListEntry js_array_proto_funcs[] = {
+ JS_CFUNC_DEF("at", 1, js_array_at ),
+ JS_CFUNC_DEF("with", 2, js_array_with ),
JS_CFUNC_DEF("concat", 1, js_array_concat ),
JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every ),
JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some ),
@@ -39766,8 +41010,10 @@ static const JSCFunctionListEntry js_array_proto_funcs[] = {
JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce ),
JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight ),
JS_CFUNC_DEF("fill", 1, js_array_fill ),
- JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, 0 ),
- JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, 1 ),
+ JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, ArrayFind ),
+ JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, ArrayFindIndex ),
+ JS_CFUNC_MAGIC_DEF("findLast", 1, js_array_find, ArrayFindLast ),
+ JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_array_find, ArrayFindLastIndex ),
JS_CFUNC_DEF("indexOf", 1, js_array_indexOf ),
JS_CFUNC_DEF("lastIndexOf", 1, js_array_lastIndexOf ),
JS_CFUNC_DEF("includes", 1, js_array_includes ),
@@ -39779,9 +41025,12 @@ static const JSCFunctionListEntry js_array_proto_funcs[] = {
JS_CFUNC_MAGIC_DEF("shift", 0, js_array_pop, 1 ),
JS_CFUNC_MAGIC_DEF("unshift", 1, js_array_push, 1 ),
JS_CFUNC_DEF("reverse", 0, js_array_reverse ),
+ JS_CFUNC_DEF("toReversed", 0, js_array_toReversed ),
JS_CFUNC_DEF("sort", 1, js_array_sort ),
+ JS_CFUNC_DEF("toSorted", 1, js_array_toSorted ),
JS_CFUNC_MAGIC_DEF("slice", 2, js_array_slice, 0 ),
JS_CFUNC_MAGIC_DEF("splice", 2, js_array_slice, 1 ),
+ JS_CFUNC_DEF("toSpliced", 2, js_array_toSpliced ),
JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin ),
JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1 ),
JS_CFUNC_MAGIC_DEF("flat", 0, js_array_flatten, 0 ),
@@ -39809,17 +41058,19 @@ static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target,
if (JS_IsException(val))
return val;
switch(JS_VALUE_GET_TAG(val)) {
-#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
+#endif
{
JSBigFloat *p = JS_VALUE_GET_PTR(val);
double d;
bf_get_float64(&p->num, &d, BF_RNDN);
JS_FreeValue(ctx, val);
- val = __JS_NewFloat64(ctx, d);
+ val = JS_NewFloat64(ctx, d);
}
break;
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_DECIMAL:
val = JS_ToStringFree(ctx, val);
if (JS_IsException(val))
@@ -39968,8 +41219,16 @@ static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,
if (base < 0)
goto fail;
}
+ if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {
+ char buf1[70], *ptr;
+ ptr = i64toa(buf1 + sizeof(buf1), JS_VALUE_GET_INT(val), base);
+ return JS_NewString(ctx, ptr);
+ }
if (JS_ToFloat64Free(ctx, &d, val))
return JS_EXCEPTION;
+ if (base != 10 && isfinite(d)) {
+ return js_dtoa_radix(ctx, d, base);
+ }
return js_dtoa(ctx, d, base, 0, JS_DTOA_VAR_FORMAT);
fail:
JS_FreeValue(ctx, val);
@@ -39993,7 +41252,7 @@ static JSValue js_number_toFixed(JSContext *ctx, JSValueConst this_val,
if (f < 0 || f > 100)
return JS_ThrowRangeError(ctx, "invalid number of digits");
if (fabs(d) >= 1e21) {
- return JS_ToStringFree(ctx, JS_NewFloat64Impl(ctx, d));
+ return JS_ToStringFree(ctx, __JS_NewFloat64(ctx, d));
} else {
return js_dtoa(ctx, d, 10, f, JS_DTOA_FRAC_FORMAT);
}
@@ -40014,7 +41273,7 @@ static JSValue js_number_toExponential(JSContext *ctx, JSValueConst this_val,
if (JS_ToInt32Sat(ctx, &f, argv[0]))
return JS_EXCEPTION;
if (!isfinite(d)) {
- return JS_ToStringFree(ctx, JS_NewFloat64Impl(ctx, d));
+ return JS_ToStringFree(ctx, __JS_NewFloat64(ctx, d));
}
if (JS_IsUndefined(argv[0])) {
flags = 0;
@@ -40046,7 +41305,7 @@ static JSValue js_number_toPrecision(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
if (!isfinite(d)) {
to_string:
- return JS_ToStringFree(ctx, JS_NewFloat64Impl(ctx, d));
+ return JS_ToStringFree(ctx, __JS_NewFloat64(ctx, d));
}
if (p < 1 || p > 100)
return JS_ThrowRangeError(ctx, "invalid number of digits");
@@ -40167,17 +41426,14 @@ static int js_string_get_own_property(JSContext *ctx,
uint32_t idx, ch;
/* This is a class exotic method: obj class_id is JS_CLASS_STRING */
- if (JS_AtomIsTaggedInt(prop)) {
+ if (__JS_AtomIsTaggedInt(prop)) {
p = JS_VALUE_GET_OBJ(obj);
if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
p1 = JS_VALUE_GET_STRING(p->u.object_data);
- idx = JS_AtomToUInt32(prop);
+ idx = __JS_AtomToUInt32(prop);
if (idx < p1->len) {
if (desc) {
- if (p1->is_wide_char)
- ch = p1->u.str16[idx];
- else
- ch = p1->u.str8[idx];
+ ch = string_get(p1, idx);
desc->flags = JS_PROP_ENUMERABLE;
desc->value = js_new_string_char(ctx, ch);
desc->getter = JS_UNDEFINED;
@@ -40200,8 +41456,8 @@ static int js_string_define_own_property(JSContext *ctx,
JSObject *p;
JSString *p1, *p2;
- if (JS_AtomIsTaggedInt(prop)) {
- idx = JS_AtomToUInt32(prop);
+ if (__JS_AtomIsTaggedInt(prop)) {
+ idx = __JS_AtomToUInt32(prop);
p = JS_VALUE_GET_OBJ(this_obj);
if (JS_VALUE_GET_TAG(p->u.object_data) != JS_TAG_STRING)
goto def;
@@ -40235,8 +41491,8 @@ static int js_string_delete_property(JSContext *ctx,
{
uint32_t idx;
- if (JS_AtomIsTaggedInt(prop)) {
- idx = JS_AtomToUInt32(prop);
+ if (__JS_AtomIsTaggedInt(prop)) {
+ idx = __JS_AtomToUInt32(prop);
if (idx < js_string_obj_get_length(ctx, obj)) {
return FALSE;
}
@@ -40332,7 +41588,7 @@ static JSValue js_string_fromCodePoint(JSContext *ctx, JSValueConst this_val,
} else {
if (JS_ToFloat64(ctx, &d, argv[i]))
goto fail;
- if (d < 0 || d > 0x10ffff || (c = (int)d) != d)
+ if (isnan(d) || d < 0 || d > 0x10ffff || (c = (int)d) != d)
goto range_error;
}
if (string_buffer_putc(b, c))
@@ -40443,10 +41699,7 @@ static JSValue js_string_charCodeAt(JSContext *ctx, JSValueConst this_val,
if (idx < 0 || idx >= p->len) {
ret = JS_NAN;
} else {
- if (p->is_wide_char)
- c = p->u.str16[idx];
- else
- c = p->u.str8[idx];
+ c = string_get(p, idx);
ret = JS_NewInt32(ctx, c);
}
JS_FreeValue(ctx, val);
@@ -40454,7 +41707,7 @@ static JSValue js_string_charCodeAt(JSContext *ctx, JSValueConst this_val,
}
static JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
+ int argc, JSValueConst *argv, int is_at)
{
JSValue val, ret;
JSString *p;
@@ -40468,13 +41721,15 @@ static JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val,
JS_FreeValue(ctx, val);
return JS_EXCEPTION;
}
+ if (idx < 0 && is_at)
+ idx += p->len;
if (idx < 0 || idx >= p->len) {
- ret = js_new_string8(ctx, NULL, 0);
- } else {
- if (p->is_wide_char)
- c = p->u.str16[idx];
+ if (is_at)
+ ret = JS_UNDEFINED;
else
- c = p->u.str8[idx];
+ ret = js_new_string8(ctx, NULL, 0);
+ } else {
+ c = string_get(p, idx);
ret = js_new_string_char(ctx, c);
}
JS_FreeValue(ctx, val);
@@ -40582,6 +41837,80 @@ static int64_t string_advance_index(JSString *p, int64_t index, BOOL unicode)
return index;
}
+/* return the position of the first invalid character in the string or
+ -1 if none */
+static int js_string_find_invalid_codepoint(JSString *p)
+{
+ int i;
+ if (!p->is_wide_char)
+ return -1;
+ for(i = 0; i < p->len; i++) {
+ uint32_t c = p->u.str16[i];
+ if (is_surrogate(c)) {
+ if (is_hi_surrogate(c) && (i + 1) < p->len
+ && is_lo_surrogate(p->u.str16[i + 1])) {
+ i++;
+ } else {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+static JSValue js_string_isWellFormed(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue str;
+ JSString *p;
+ BOOL ret;
+
+ str = JS_ToStringCheckObject(ctx, this_val);
+ if (JS_IsException(str))
+ return JS_EXCEPTION;
+ p = JS_VALUE_GET_STRING(str);
+ ret = (js_string_find_invalid_codepoint(p) < 0);
+ JS_FreeValue(ctx, str);
+ return JS_NewBool(ctx, ret);
+}
+
+static JSValue js_string_toWellFormed(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue str, ret;
+ JSString *p;
+ int i;
+
+ str = JS_ToStringCheckObject(ctx, this_val);
+ if (JS_IsException(str))
+ return JS_EXCEPTION;
+
+ p = JS_VALUE_GET_STRING(str);
+ /* avoid reallocating the string if it is well-formed */
+ i = js_string_find_invalid_codepoint(p);
+ if (i < 0)
+ return str;
+
+ ret = js_new_string16(ctx, p->u.str16, p->len);
+ JS_FreeValue(ctx, str);
+ if (JS_IsException(ret))
+ return JS_EXCEPTION;
+
+ p = JS_VALUE_GET_STRING(ret);
+ for (; i < p->len; i++) {
+ uint32_t c = p->u.str16[i];
+ if (is_surrogate(c)) {
+ if (is_hi_surrogate(c) && (i + 1) < p->len
+ && is_lo_surrogate(p->u.str16[i + 1])) {
+ i++;
+ } else {
+ p->u.str16[i] = 0xFFFD;
+ }
+ }
+ }
+ return ret;
+}
+
static JSValue js_string_indexOf(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int lastIndexOf)
{
@@ -40664,7 +41993,7 @@ static JSValue js_string_includes(JSContext *ctx, JSValueConst this_val,
ret = js_is_regexp(ctx, argv[0]);
if (ret) {
if (ret > 0)
- JS_ThrowTypeError(ctx, "regex not supported");
+ JS_ThrowTypeError(ctx, "regexp not supported");
goto fail;
}
v = JS_ToString(ctx, argv[0]);
@@ -40788,7 +42117,7 @@ static JSValue js_string_match(JSContext *ctx, JSValueConst this_val,
JS_FreeValue(ctx, S);
return JS_EXCEPTION;
}
- result = JS_InvokeFree(ctx, rx, atom, 1, &S);
+ result = JS_InvokeFree(ctx, rx, atom, 1, (JSValueConst *)&S);
JS_FreeValue(ctx, S);
return result;
}
@@ -41226,7 +42555,7 @@ static JSValue js_string_pad(JSContext *ctx, JSValueConst this_val,
}
}
if (n > JS_STRING_LEN_MAX) {
- JS_ThrowInternalError(ctx, "string too long");
+ JS_ThrowRangeError(ctx, "invalid string length");
goto fail2;
}
if (string_buffer_init(ctx, b, n))
@@ -41288,8 +42617,9 @@ static JSValue js_string_repeat(JSContext *ctx, JSValueConst this_val,
len = p->len;
if (len == 0 || n == 1)
return str;
+ // XXX: potential arithmetic overflow
if (val * len > JS_STRING_LEN_MAX) {
- JS_ThrowInternalError(ctx, "string too long");
+ JS_ThrowRangeError(ctx, "invalid string length");
goto fail;
}
if (string_buffer_init2(ctx, b, n * len, p->is_wide_char))
@@ -41352,10 +42682,10 @@ static int string_prevc(JSString *p, int *pidx)
idx--;
if (p->is_wide_char) {
c = p->u.str16[idx];
- if (c >= 0xdc00 && c < 0xe000 && idx > 0) {
+ if (is_lo_surrogate(c) && idx > 0) {
c1 = p->u.str16[idx - 1];
- if (c1 >= 0xd800 && c1 <= 0xdc00) {
- c = (((c1 & 0x3ff) << 10) | (c & 0x3ff)) + 0x10000;
+ if (is_hi_surrogate(c1)) {
+ c = from_surrogate(c1, c);
idx--;
}
}
@@ -41394,26 +42724,6 @@ static BOOL test_final_sigma(JSString *p, int sigma_pos)
return !lre_is_cased(c1);
}
-static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
-{
- JSValue a, b;
- int cmp;
-
- a = JS_ToStringCheckObject(ctx, this_val);
- if (JS_IsException(a))
- return JS_EXCEPTION;
- b = JS_ToString(ctx, argv[0]);
- if (JS_IsException(b)) {
- JS_FreeValue(ctx, a);
- return JS_EXCEPTION;
- }
- cmp = js_string_compare(ctx, JS_VALUE_GET_STRING(a), JS_VALUE_GET_STRING(b));
- JS_FreeValue(ctx, a);
- JS_FreeValue(ctx, b);
- return JS_NewInt32(ctx, cmp);
-}
-
static JSValue js_string_toLowerCase(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int to_lower)
{
@@ -41499,23 +42809,38 @@ static JSValue JS_NewUTF32String(JSContext *ctx, const uint32_t *buf, int len)
return JS_EXCEPTION;
}
+static int js_string_normalize1(JSContext *ctx, uint32_t **pout_buf,
+ JSValueConst val,
+ UnicodeNormalizationEnum n_type)
+{
+ int buf_len, out_len;
+ uint32_t *buf, *out_buf;
+
+ buf_len = JS_ToUTF32String(ctx, &buf, val);
+ if (buf_len < 0)
+ return -1;
+ out_len = unicode_normalize(&out_buf, buf, buf_len, n_type,
+ ctx->rt, (DynBufReallocFunc *)js_realloc_rt);
+ js_free(ctx, buf);
+ if (out_len < 0)
+ return -1;
+ *pout_buf = out_buf;
+ return out_len;
+}
+
static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
const char *form, *p;
size_t form_len;
- int is_compat, buf_len, out_len;
+ int is_compat, out_len;
UnicodeNormalizationEnum n_type;
JSValue val;
- uint32_t *buf, *out_buf;
+ uint32_t *out_buf;
val = JS_ToStringCheckObject(ctx, this_val);
if (JS_IsException(val))
return val;
- buf_len = JS_ToUTF32String(ctx, &buf, val);
- JS_FreeValue(ctx, val);
- if (buf_len < 0)
- return JS_EXCEPTION;
if (argc == 0 || JS_IsUndefined(argv[0])) {
n_type = UNICODE_NFC;
@@ -41541,22 +42866,96 @@ static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val,
JS_FreeCString(ctx, form);
JS_ThrowRangeError(ctx, "bad normalization form");
fail1:
- js_free(ctx, buf);
+ JS_FreeValue(ctx, val);
return JS_EXCEPTION;
}
JS_FreeCString(ctx, form);
}
- out_len = unicode_normalize(&out_buf, buf, buf_len, n_type,
- ctx->rt, (DynBufReallocFunc *)js_realloc_rt);
- js_free(ctx, buf);
+ out_len = js_string_normalize1(ctx, &out_buf, val, n_type);
+ JS_FreeValue(ctx, val);
if (out_len < 0)
return JS_EXCEPTION;
val = JS_NewUTF32String(ctx, out_buf, out_len);
js_free(ctx, out_buf);
return val;
}
-#endif /* CONFIG_ALL_UNICODE */
+
+/* return < 0, 0 or > 0 */
+static int js_UTF32_compare(const uint32_t *buf1, int buf1_len,
+ const uint32_t *buf2, int buf2_len)
+{
+ int i, len, c, res;
+ len = min_int(buf1_len, buf2_len);
+ for(i = 0; i < len; i++) {
+ /* Note: range is limited so a subtraction is valid */
+ c = buf1[i] - buf2[i];
+ if (c != 0)
+ return c;
+ }
+ if (buf1_len == buf2_len)
+ res = 0;
+ else if (buf1_len < buf2_len)
+ res = -1;
+ else
+ res = 1;
+ return res;
+}
+
+static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue a, b;
+ int cmp, a_len, b_len;
+ uint32_t *a_buf, *b_buf;
+
+ a = JS_ToStringCheckObject(ctx, this_val);
+ if (JS_IsException(a))
+ return JS_EXCEPTION;
+ b = JS_ToString(ctx, argv[0]);
+ if (JS_IsException(b)) {
+ JS_FreeValue(ctx, a);
+ return JS_EXCEPTION;
+ }
+ a_len = js_string_normalize1(ctx, &a_buf, a, UNICODE_NFC);
+ JS_FreeValue(ctx, a);
+ if (a_len < 0) {
+ JS_FreeValue(ctx, b);
+ return JS_EXCEPTION;
+ }
+
+ b_len = js_string_normalize1(ctx, &b_buf, b, UNICODE_NFC);
+ JS_FreeValue(ctx, b);
+ if (b_len < 0) {
+ js_free(ctx, a_buf);
+ return JS_EXCEPTION;
+ }
+ cmp = js_UTF32_compare(a_buf, a_len, b_buf, b_len);
+ js_free(ctx, a_buf);
+ js_free(ctx, b_buf);
+ return JS_NewInt32(ctx, cmp);
+}
+#else /* CONFIG_ALL_UNICODE */
+static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue a, b;
+ int cmp;
+
+ a = JS_ToStringCheckObject(ctx, this_val);
+ if (JS_IsException(a))
+ return JS_EXCEPTION;
+ b = JS_ToString(ctx, argv[0]);
+ if (JS_IsException(b)) {
+ JS_FreeValue(ctx, a);
+ return JS_EXCEPTION;
+ }
+ cmp = js_string_compare(ctx, JS_VALUE_GET_STRING(a), JS_VALUE_GET_STRING(b));
+ JS_FreeValue(ctx, a);
+ JS_FreeValue(ctx, b);
+ return JS_NewInt32(ctx, cmp);
+}
+#endif /* !CONFIG_ALL_UNICODE */
/* also used for String.prototype.valueOf */
static JSValue js_string_toString(JSContext *ctx, JSValueConst this_val,
@@ -41728,10 +43127,13 @@ static const JSCFunctionListEntry js_string_funcs[] = {
static const JSCFunctionListEntry js_string_proto_funcs[] = {
JS_PROP_INT32_DEF("length", 0, JS_PROP_CONFIGURABLE ),
+ JS_CFUNC_MAGIC_DEF("at", 1, js_string_charAt, 1 ),
JS_CFUNC_DEF("charCodeAt", 1, js_string_charCodeAt ),
- JS_CFUNC_DEF("charAt", 1, js_string_charAt ),
+ JS_CFUNC_MAGIC_DEF("charAt", 1, js_string_charAt, 0 ),
JS_CFUNC_DEF("concat", 1, js_string_concat ),
JS_CFUNC_DEF("codePointAt", 1, js_string_codePointAt ),
+ JS_CFUNC_DEF("isWellFormed", 0, js_string_isWellFormed ),
+ JS_CFUNC_DEF("toWellFormed", 0, js_string_toWellFormed ),
JS_CFUNC_MAGIC_DEF("indexOf", 1, js_string_indexOf, 0 ),
JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_string_indexOf, 1 ),
JS_CFUNC_MAGIC_DEF("includes", 1, js_string_includes, 0 ),
@@ -41837,7 +43239,7 @@ static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
uint32_t tag;
if (unlikely(argc == 0)) {
- return JS_NewFloat64Impl(ctx, is_max ? INFINITY : -INFINITY);
+ return __JS_NewFloat64(ctx, is_max ? INFINITY : -INFINITY);
}
tag = JS_VALUE_GET_TAG(argv[0]);
@@ -41951,14 +43353,16 @@ static double js_math_fround(double a)
static JSValue js_math_imul(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
- int a, b;
+ uint32_t a, b, c;
+ int32_t d;
- if (JS_ToInt32(ctx, &a, argv[0]))
+ if (JS_ToUint32(ctx, &a, argv[0]))
return JS_EXCEPTION;
- if (JS_ToInt32(ctx, &b, argv[1]))
+ if (JS_ToUint32(ctx, &b, argv[1]))
return JS_EXCEPTION;
- /* purposely ignoring overflow */
- return JS_NewInt32(ctx, a * b);
+ c = a * b;
+ memcpy(&d, &c, sizeof(d));
+ return JS_NewInt32(ctx, d);
}
static JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val,
@@ -42010,7 +43414,7 @@ static JSValue js_math_random(JSContext *ctx, JSValueConst this_val,
v = xorshift64star(&ctx->random_state);
/* 1.0 <= u.d < 2 */
u.u64 = ((uint64_t)0x3ff << 52) | (v >> 12);
- return JS_NewFloat64Impl(ctx, u.d - 1.0);
+ return __JS_NewFloat64(ctx, u.d - 1.0);
}
// MSVC inexplicably refuses to initialize the array below with
@@ -42074,46 +43478,12 @@ static const JSCFunctionListEntry js_math_obj[] = {
/* Date */
-#if 0
-/* OS dependent: return the UTC time in ms since 1970. */
-static JSValue js___date_now(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
-{
- int64_t d;
- struct timeval tv;
- gettimeofday(&tv, NULL);
- d = (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
- return JS_NewInt64(ctx, d);
-}
-#endif
-
-/* OS dependent: return the UTC time in microseconds since 1970. */
-static JSValue js___date_clock(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
-{
- int64_t d;
-#ifdef _MSC_VER
- SYSTEMTIME st;
- GetSystemTime(&st);
- SystemTimeToFileTime(&st, (FILETIME *) &d);
- d /= 10;
-#else
- struct timeval tv;
- gettimeofday(&tv, NULL);
- d = (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
-#endif
- return JS_NewInt64(ctx, d);
-}
-
/* OS dependent. d = argv[0] is in ms from 1970. Return the difference
between UTC time and local time 'd' in minutes */
-static int getTimezoneOffset(int64_t time) {
-#if defined(_WIN32)
- /* XXX: TODO */
- return 0;
-#else
+static int getTimezoneOffset(int64_t time)
+{
time_t ti;
- struct tm tm;
+ int res;
time /= 1000; /* convert to seconds */
if (sizeof(time_t) == 4) {
@@ -42137,9 +43507,27 @@ static int getTimezoneOffset(int64_t time) {
}
}
ti = time;
- localtime_r(&ti, &tm);
- return -tm.tm_gmtoff / 60;
+#if defined(_WIN32)
+ {
+ struct tm *tm;
+ time_t gm_ti, loc_ti;
+
+ tm = gmtime(&ti);
+ gm_ti = mktime(tm);
+
+ tm = localtime(&ti);
+ loc_ti = mktime(tm);
+
+ res = (gm_ti - loc_ti) / 60;
+ }
+#else
+ {
+ struct tm tm;
+ localtime_r(&ti, &tm);
+ res = -tm.tm_gmtoff / 60;
+ }
#endif
+ return res;
}
#if 0
@@ -42151,7 +43539,7 @@ static JSValue js___date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val
if (JS_ToFloat64(ctx, &dd, argv[0]))
return JS_EXCEPTION;
if (isnan(dd))
- return __JS_NewFloat64(ctx, dd);
+ return JS_NewFloat64(ctx, dd);
else
return JS_NewInt32(ctx, getTimezoneOffset((int64_t)dd));
}
@@ -42216,6 +43604,9 @@ static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
/* XXX: re_flags = LRE_FLAG_OCTAL unless strict mode? */
for (i = 0; i < len; i++) {
switch(str[i]) {
+ case 'd':
+ mask = LRE_FLAG_INDICES;
+ break;
case 'g':
mask = LRE_FLAG_GLOBAL;
break;
@@ -42229,7 +43620,7 @@ static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
mask = LRE_FLAG_DOTALL;
break;
case 'u':
- mask = LRE_FLAG_UTF16;
+ mask = LRE_FLAG_UNICODE;
break;
case 'y':
mask = LRE_FLAG_STICKY;
@@ -42247,7 +43638,7 @@ static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
JS_FreeCString(ctx, str);
}
- str = JS_ToCStringLen2(ctx, &len, pattern, !(re_flags & LRE_FLAG_UTF16));
+ str = JS_ToCStringLen2(ctx, &len, pattern, !(re_flags & LRE_FLAG_UNICODE));
if (!str)
return JS_EXCEPTION;
re_bytecode_buf = lre_compile(&re_bytecode_len, error_msg,
@@ -42548,7 +43939,7 @@ static JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mas
}
flags = lre_get_flags(re->bytecode->u.str8);
- return JS_NewBool(ctx, (flags & mask) != 0);
+ return JS_NewBool(ctx, flags & mask);
}
static JSValue js_regexp_get_flags(JSContext *ctx, JSValueConst this_val)
@@ -42559,6 +43950,11 @@ static JSValue js_regexp_get_flags(JSContext *ctx, JSValueConst this_val)
if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
return JS_ThrowTypeErrorNotAnObject(ctx);
+ res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "hasIndices"));
+ if (res < 0)
+ goto exception;
+ if (res)
+ *p++ = 'd';
res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, JS_ATOM_global));
if (res < 0)
goto exception;
@@ -42638,25 +44034,32 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val,
{
JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
JSString *str;
- JSValue str_val, obj, val, groups = JS_UNDEFINED;
+ JSValue t, ret, str_val, obj, val, groups;
+ JSValue indices, indices_groups;
uint8_t *re_bytecode;
- int ret;
uint8_t **capture, *str_buf;
- int capture_count, shift, i, re_flags;
+ int rc, capture_count, shift, i, re_flags;
int64_t last_index;
const char *group_name_ptr;
if (!re)
return JS_EXCEPTION;
+
str_val = JS_ToString(ctx, argv[0]);
if (JS_IsException(str_val))
- return str_val;
- val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
- if (JS_IsException(val) ||
- JS_ToLengthFree(ctx, &last_index, val)) {
- JS_FreeValue(ctx, str_val);
return JS_EXCEPTION;
- }
+
+ ret = JS_EXCEPTION;
+ obj = JS_NULL;
+ groups = JS_UNDEFINED;
+ indices = JS_UNDEFINED;
+ indices_groups = JS_UNDEFINED;
+ capture = NULL;
+
+ val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
+ if (JS_IsException(val) || JS_ToLengthFree(ctx, &last_index, val))
+ goto fail;
+
re_bytecode = re->bytecode->u.str8;
re_flags = lre_get_flags(re_bytecode);
if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
@@ -42664,27 +44067,23 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val,
}
str = JS_VALUE_GET_STRING(str_val);
capture_count = lre_get_capture_count(re_bytecode);
- capture = NULL;
if (capture_count > 0) {
capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2);
- if (!capture) {
- JS_FreeValue(ctx, str_val);
- return JS_EXCEPTION;
- }
+ if (!capture)
+ goto fail;
}
shift = str->is_wide_char;
str_buf = str->u.str8;
if (last_index > str->len) {
- ret = 2;
+ rc = 2;
} else {
- ret = lre_exec(capture, re_bytecode,
- str_buf, last_index, str->len,
- shift, ctx);
+ rc = lre_exec(capture, re_bytecode,
+ str_buf, last_index, str->len,
+ shift, ctx);
}
- obj = JS_NULL;
- if (ret != 1) {
- if (ret >= 0) {
- if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
+ if (rc != 1) {
+ if (rc >= 0) {
+ if (rc == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
JS_NewInt32(ctx, 0)) < 0)
goto fail;
@@ -42693,7 +44092,6 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val,
JS_ThrowInternalError(ctx, "out of memory in regexp execution");
goto fail;
}
- JS_FreeValue(ctx, str_val);
} else {
int prop_flags;
if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {
@@ -42711,52 +44109,124 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val,
if (JS_IsException(groups))
goto fail;
}
+ if (re_flags & LRE_FLAG_INDICES) {
+ indices = JS_NewArray(ctx);
+ if (JS_IsException(indices))
+ goto fail;
+ if (group_name_ptr) {
+ indices_groups = JS_NewObjectProto(ctx, JS_NULL);
+ if (JS_IsException(indices_groups))
+ goto fail;
+ }
+ }
for(i = 0; i < capture_count; i++) {
- int start, end;
+ const char *name = NULL;
+ uint8_t **match = &capture[2 * i];
+ int start = -1;
+ int end = -1;
JSValue val;
- if (capture[2 * i] == NULL ||
- capture[2 * i + 1] == NULL) {
+
+ if (group_name_ptr && i > 0) {
+ if (*group_name_ptr) name = group_name_ptr;
+ group_name_ptr += strlen(group_name_ptr) + 1;
+ }
+
+ if (match[0] && match[1]) {
+ start = (match[0] - str_buf) >> shift;
+ end = (match[1] - str_buf) >> shift;
+ }
+
+ if (!JS_IsUndefined(indices)) {
val = JS_UNDEFINED;
- } else {
- start = (capture[2 * i] - str_buf) >> shift;
- end = (capture[2 * i + 1] - str_buf) >> shift;
+ if (start != -1) {
+ val = JS_NewArray(ctx);
+ if (JS_IsException(val))
+ goto fail;
+ if (JS_DefinePropertyValueUint32(ctx, val, 0,
+ JS_NewInt32(ctx, start),
+ prop_flags) < 0) {
+ JS_FreeValue(ctx, val);
+ goto fail;
+ }
+ if (JS_DefinePropertyValueUint32(ctx, val, 1,
+ JS_NewInt32(ctx, end),
+ prop_flags) < 0) {
+ JS_FreeValue(ctx, val);
+ goto fail;
+ }
+ }
+ if (name && !JS_IsUndefined(indices_groups)) {
+ val = JS_DupValue(ctx, val);
+ if (JS_DefinePropertyValueStr(ctx, indices_groups,
+ name, val, prop_flags) < 0) {
+ JS_FreeValue(ctx, val);
+ goto fail;
+ }
+ }
+ if (JS_DefinePropertyValueUint32(ctx, indices, i, val,
+ prop_flags) < 0) {
+ goto fail;
+ }
+ }
+
+ val = JS_UNDEFINED;
+ if (start != -1) {
val = js_sub_string(ctx, str, start, end);
if (JS_IsException(val))
goto fail;
}
- if (group_name_ptr && i > 0) {
- if (*group_name_ptr) {
- if (JS_DefinePropertyValueStr(ctx, groups, group_name_ptr,
- JS_DupValue(ctx, val),
- prop_flags) < 0) {
- JS_FreeValue(ctx, val);
- goto fail;
- }
+
+ if (name) {
+ if (JS_DefinePropertyValueStr(ctx, groups, name,
+ JS_DupValue(ctx, val),
+ prop_flags) < 0) {
+ JS_FreeValue(ctx, val);
+ goto fail;
}
- group_name_ptr += strlen(group_name_ptr) + 1;
}
+
if (JS_DefinePropertyValueUint32(ctx, obj, i, val, prop_flags) < 0)
goto fail;
}
+
+ t = groups, groups = JS_UNDEFINED;
if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_groups,
- groups, prop_flags) < 0)
+ t, prop_flags) < 0) {
goto fail;
- if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_index,
- JS_NewInt32(ctx, (capture[0] - str_buf) >> shift), prop_flags) < 0)
+ }
+
+ t = JS_NewInt32(ctx, (capture[0] - str_buf) >> shift);
+ if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_index, t, prop_flags) < 0)
goto fail;
- if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_input, str_val, prop_flags) < 0)
- goto fail1;
+
+ t = str_val, str_val = JS_UNDEFINED;
+ if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_input, t, prop_flags) < 0)
+ goto fail;
+
+ if (!JS_IsUndefined(indices)) {
+ t = indices_groups, indices_groups = JS_UNDEFINED;
+ if (JS_DefinePropertyValue(ctx, indices, JS_ATOM_groups,
+ t, prop_flags) < 0) {
+ goto fail;
+ }
+ t = indices, indices = JS_UNDEFINED;
+ if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_indices,
+ t, prop_flags) < 0) {
+ goto fail;
+ }
+ }
}
- js_free(ctx, capture);
- return obj;
+ ret = obj;
+ obj = JS_UNDEFINED;
fail:
- JS_FreeValue(ctx, groups);
+ JS_FreeValue(ctx, indices_groups);
+ JS_FreeValue(ctx, indices);
JS_FreeValue(ctx, str_val);
-fail1:
+ JS_FreeValue(ctx, groups);
JS_FreeValue(ctx, obj);
js_free(ctx, capture);
- return JS_EXCEPTION;
+ return ret;
}
/* delete portions of a string that match a given regex */
@@ -42835,7 +44305,7 @@ static JSValue JS_RegExpDelete(JSContext *ctx, JSValueConst this_val, JSValueCon
break;
}
if (end == start) {
- if (!(re_flags & LRE_FLAG_UTF16) || (unsigned)end >= str->len || !str->is_wide_char) {
+ if (!(re_flags & LRE_FLAG_UNICODE) || (unsigned)end >= str->len || !str->is_wide_char) {
end++;
} else {
string_getc(str, &end);
@@ -42908,7 +44378,7 @@ static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val,
{
// [Symbol.match](str)
JSValueConst rx = this_val;
- JSValue A, S, result, matchStr;
+ JSValue A, S, flags, result, matchStr;
int global, n, fullUnicode, isEmpty;
JSString *p;
@@ -42916,16 +44386,23 @@ static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val,
return JS_ThrowTypeErrorNotAnObject(ctx);
A = JS_UNDEFINED;
+ flags = JS_UNDEFINED;
result = JS_UNDEFINED;
matchStr = JS_UNDEFINED;
S = JS_ToString(ctx, argv[0]);
if (JS_IsException(S))
goto exception;
- global = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_global));
- if (global < 0)
+ flags = JS_GetProperty(ctx, rx, JS_ATOM_flags);
+ if (JS_IsException(flags))
+ goto exception;
+ flags = JS_ToStringFree(ctx, flags);
+ if (JS_IsException(flags))
goto exception;
+ p = JS_VALUE_GET_STRING(flags);
+ // TODO(bnoordhuis) query 'u' flag the same way?
+ global = (-1 != string_indexof_char(p, 'g', 0));
if (!global) {
A = JS_RegExpExec(ctx, rx, S);
} else {
@@ -42969,12 +44446,14 @@ static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val,
}
}
JS_FreeValue(ctx, result);
+ JS_FreeValue(ctx, flags);
JS_FreeValue(ctx, S);
return A;
exception:
JS_FreeValue(ctx, A);
JS_FreeValue(ctx, result);
+ JS_FreeValue(ctx, flags);
JS_FreeValue(ctx, S);
return JS_EXCEPTION;
}
@@ -43217,8 +44696,8 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
// [Symbol.replace](str, rep)
JSValueConst rx = this_val, rep = argv[1];
JSValueConst args[6];
- JSValue str, rep_val, matched, tab, rep_str, namedCaptures, res;
- JSString *sp, *rp;
+ JSValue flags, str, rep_val, matched, tab, rep_str, namedCaptures, res;
+ JSString *p, *sp, *rp;
StringBuffer b_s, *b = &b_s;
ValueBuffer v_b, *results = &v_b;
int nextSourcePosition, n, j, functionalReplace, is_global, fullUnicode;
@@ -43234,6 +44713,7 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
rep_val = JS_UNDEFINED;
matched = JS_UNDEFINED;
tab = JS_UNDEFINED;
+ flags = JS_UNDEFINED;
rep_str = JS_UNDEFINED;
namedCaptures = JS_UNDEFINED;
@@ -43250,10 +44730,18 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
goto exception;
rp = JS_VALUE_GET_STRING(rep_val);
}
- fullUnicode = 0;
- is_global = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_global));
- if (is_global < 0)
+
+ flags = JS_GetProperty(ctx, rx, JS_ATOM_flags);
+ if (JS_IsException(flags))
goto exception;
+ flags = JS_ToStringFree(ctx, flags);
+ if (JS_IsException(flags))
+ goto exception;
+ p = JS_VALUE_GET_STRING(flags);
+
+ // TODO(bnoordhuis) query 'u' flag the same way?
+ fullUnicode = 0;
+ is_global = (-1 != string_indexof_char(p, 'g', 0));
if (is_global) {
fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode));
if (fullUnicode < 0)
@@ -43387,6 +44875,7 @@ done1:
value_buffer_free(results);
JS_FreeValue(ctx, rep_val);
JS_FreeValue(ctx, matched);
+ JS_FreeValue(ctx, flags);
JS_FreeValue(ctx, tab);
JS_FreeValue(ctx, rep_str);
JS_FreeValue(ctx, namedCaptures);
@@ -43587,12 +45076,13 @@ static const JSCFunctionListEntry js_regexp_funcs[] = {
static const JSCFunctionListEntry js_regexp_proto_funcs[] = {
JS_CGETSET_DEF("flags", js_regexp_get_flags, NULL ),
JS_CGETSET_DEF("source", js_regexp_get_source, NULL ),
- JS_CGETSET_MAGIC_DEF("global", js_regexp_get_flag, NULL, 1 ),
- JS_CGETSET_MAGIC_DEF("ignoreCase", js_regexp_get_flag, NULL, 2 ),
- JS_CGETSET_MAGIC_DEF("multiline", js_regexp_get_flag, NULL, 4 ),
- JS_CGETSET_MAGIC_DEF("dotAll", js_regexp_get_flag, NULL, 8 ),
- JS_CGETSET_MAGIC_DEF("unicode", js_regexp_get_flag, NULL, 16 ),
- JS_CGETSET_MAGIC_DEF("sticky", js_regexp_get_flag, NULL, 32 ),
+ JS_CGETSET_MAGIC_DEF("global", js_regexp_get_flag, NULL, LRE_FLAG_GLOBAL ),
+ JS_CGETSET_MAGIC_DEF("ignoreCase", js_regexp_get_flag, NULL, LRE_FLAG_IGNORECASE ),
+ JS_CGETSET_MAGIC_DEF("multiline", js_regexp_get_flag, NULL, LRE_FLAG_MULTILINE ),
+ JS_CGETSET_MAGIC_DEF("dotAll", js_regexp_get_flag, NULL, LRE_FLAG_DOTALL ),
+ JS_CGETSET_MAGIC_DEF("unicode", js_regexp_get_flag, NULL, LRE_FLAG_UNICODE ),
+ JS_CGETSET_MAGIC_DEF("sticky", js_regexp_get_flag, NULL, LRE_FLAG_STICKY ),
+ JS_CGETSET_MAGIC_DEF("hasIndices", js_regexp_get_flag, NULL, LRE_FLAG_INDICES ),
JS_CFUNC_DEF("exec", 1, js_regexp_exec ),
JS_CFUNC_DEF("compile", 2, js_regexp_compile ),
JS_CFUNC_DEF("test", 1, js_regexp_test ),
@@ -43750,7 +45240,7 @@ static JSValue json_parse_value(JSParseState *s)
case TOK_IDENT:
if (s->token.u.ident.atom == JS_ATOM_false ||
s->token.u.ident.atom == JS_ATOM_true) {
- val = JS_NewBool(ctx, (s->token.u.ident.atom == JS_ATOM_true));
+ val = JS_NewBool(ctx, s->token.u.ident.atom == JS_ATOM_true);
} else if (s->token.u.ident.atom == JS_ATOM_null) {
val = JS_NULL;
} else {
@@ -43762,7 +45252,7 @@ static JSValue json_parse_value(JSParseState *s)
default:
def_token:
if (s->token.val == TOK_EOF) {
- js_parse_error(s, "unexpected end of input");
+ js_parse_error(s, "Unexpected end of JSON input");
} else {
js_parse_error(s, "unexpected token: '%.*s'",
(int)(s->buf_ptr - s->token.ptr), s->token.ptr);
@@ -43929,24 +45419,27 @@ static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
JSValue v;
JSValueConst args[2];
- if (JS_IsObject(val)
+ /* check for object.toJSON method */
+ /* ECMA specifies this is done only for Object and BigInt */
+ /* we do it for BigFloat and BigDecimal as an extension */
+ if (JS_IsObject(val) || JS_IsBigInt(ctx, val)
#ifdef CONFIG_BIGNUM
- || JS_IsBigInt(ctx, val) /* XXX: probably useless */
+ || JS_IsBigFloat(val) || JS_IsBigDecimal(val)
#endif
) {
- JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON);
- if (JS_IsException(f))
+ JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON);
+ if (JS_IsException(f))
+ goto exception;
+ if (JS_IsFunction(ctx, f)) {
+ v = JS_CallFree(ctx, f, val, 1, &key);
+ JS_FreeValue(ctx, val);
+ val = v;
+ if (JS_IsException(val))
goto exception;
- if (JS_IsFunction(ctx, f)) {
- v = JS_CallFree(ctx, f, val, 1, &key);
- JS_FreeValue(ctx, val);
- val = v;
- if (JS_IsException(val))
- goto exception;
- } else {
- JS_FreeValue(ctx, f);
- }
+ } else {
+ JS_FreeValue(ctx, f);
}
+ }
if (!JS_IsUndefined(jsc->replacer_func)) {
args[0] = key;
@@ -43965,13 +45458,12 @@ static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
case JS_TAG_STRING:
case JS_TAG_INT:
case JS_TAG_FLOAT64:
-#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_FLOAT:
-#endif
case JS_TAG_BOOL:
case JS_TAG_NULL:
-#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_FLOAT:
+ case JS_TAG_BIG_DECIMAL:
#endif
case JS_TAG_EXCEPTION:
return val;
@@ -44002,37 +45494,31 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
tab = JS_UNDEFINED;
prop = JS_UNDEFINED;
- switch (JS_VALUE_GET_NORM_TAG(val)) {
- case JS_TAG_OBJECT:
+ if (JS_IsObject(val)) {
p = JS_VALUE_GET_OBJ(val);
cl = p->class_id;
if (cl == JS_CLASS_STRING) {
val = JS_ToStringFree(ctx, val);
if (JS_IsException(val))
goto exception;
- val = JS_ToQuotedStringFree(ctx, val);
- if (JS_IsException(val))
- goto exception;
- return string_buffer_concat_value_free(jsc->b, val);
+ goto concat_primitive;
} else if (cl == JS_CLASS_NUMBER) {
val = JS_ToNumberFree(ctx, val);
if (JS_IsException(val))
goto exception;
- return string_buffer_concat_value_free(jsc->b, val);
- } else if (cl == JS_CLASS_BOOLEAN) {
- ret = string_buffer_concat_value(jsc->b, p->u.object_data);
- JS_FreeValue(ctx, val);
- return ret;
- }
+ goto concat_primitive;
+ } else if (cl == JS_CLASS_BOOLEAN || cl == JS_CLASS_BIG_INT
#ifdef CONFIG_BIGNUM
- else if (cl == JS_CLASS_BIG_FLOAT) {
- return string_buffer_concat_value_free(jsc->b, val);
- } else if (cl == JS_CLASS_BIG_INT) {
- JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify");
- goto exception;
- }
+ || cl == JS_CLASS_BIG_FLOAT
+ || cl == JS_CLASS_BIG_DECIMAL
#endif
- v = js_array_includes(ctx, jsc->stack, 1, &val);
+ )
+ {
+ /* This will thow the same error as for the primitive object */
+ set_value(ctx, &val, JS_DupValue(ctx, p->u.object_data));
+ goto concat_primitive;
+ }
+ v = js_array_includes(ctx, jsc->stack, 1, (JSValueConst *)&val);
if (JS_IsException(v))
goto exception;
if (JS_ToBoolFree(ctx, v)) {
@@ -44053,7 +45539,7 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
sep = JS_DupValue(ctx, jsc->empty);
sep1 = JS_DupValue(ctx, jsc->empty);
}
- v = js_array_push(ctx, jsc->stack, 1, &val, 0);
+ v = js_array_push(ctx, jsc->stack, 1, (JSValueConst *)&val, 0);
if (check_exception_free(ctx, v))
goto exception;
ret = JS_IsArray(ctx, val);
@@ -44093,7 +45579,7 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
if (!JS_IsUndefined(jsc->property_list))
tab = JS_DupValue(ctx, jsc->property_list);
else
- tab = js_object_keys(ctx, JS_UNDEFINED, 1, &val, JS_ITERATOR_KIND_KEY);
+ tab = js_object_keys(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val, JS_ITERATOR_KIND_KEY);
if (JS_IsException(tab))
goto exception;
if (js_get_length64(ctx, &len, tab))
@@ -44128,7 +45614,7 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
has_content = TRUE;
}
}
- if (has_content && JS_VALUE_GET_STRING(jsc->gap)->len != 0) {
+ if (has_content && !JS_IsEmptyString(jsc->gap)) {
string_buffer_putc8(jsc->b, '\n');
string_buffer_concat_value(jsc->b, indent);
}
@@ -44143,6 +45629,9 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
JS_FreeValue(ctx, indent1);
JS_FreeValue(ctx, prop);
return 0;
+ }
+ concat_primitive:
+ switch (JS_VALUE_GET_NORM_TAG(val)) {
case JS_TAG_STRING:
val = JS_ToQuotedStringFree(ctx, val);
if (JS_IsException(val))
@@ -44154,18 +45643,18 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
}
goto concat_value;
case JS_TAG_INT:
-#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_FLOAT:
-#endif
case JS_TAG_BOOL:
case JS_TAG_NULL:
concat_value:
return string_buffer_concat_value_free(jsc->b, val);
-#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
- JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify");
- goto exception;
+#ifdef CONFIG_BIGNUM
+ case JS_TAG_BIG_FLOAT:
+ case JS_TAG_BIG_DECIMAL:
#endif
+ /* reject big numbers: use toJSON method to override */
+ JS_ThrowTypeError(ctx, "Do not know how to serialize a BigInt");
+ goto exception;
default:
JS_FreeValue(ctx, val);
return 0;
@@ -44241,7 +45730,7 @@ JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
continue;
}
present = js_array_includes(ctx, jsc->property_list,
- 1, &v);
+ 1, (JSValueConst *)&v);
if (JS_IsException(present)) {
JS_FreeValue(ctx, v);
goto exception;
@@ -44365,7 +45854,7 @@ static JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val,
tab = build_arg_list(ctx, &len, array_arg);
if (!tab)
return JS_EXCEPTION;
- ret = JS_CallConstructor2(ctx, func, new_target, len, tab);
+ ret = JS_CallConstructor2(ctx, func, new_target, len, (JSValueConst *)tab);
free_arg_list(ctx, tab, len);
return ret;
}
@@ -44455,8 +45944,8 @@ static JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val,
atom = JS_ValueToAtom(ctx, prop);
if (unlikely(atom == JS_ATOM_NULL))
return JS_EXCEPTION;
- ret = JS_SetPropertyGeneric(ctx, obj, atom,
- JS_DupValue(ctx, val), receiver, 0);
+ ret = JS_SetPropertyInternal(ctx, obj, atom,
+ JS_DupValue(ctx, val), receiver, 0);
JS_FreeAtom(ctx, atom);
if (ret < 0)
return JS_EXCEPTION;
@@ -44570,7 +46059,7 @@ static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj)
return JS_EXCEPTION;
if (JS_IsUndefined(method))
return JS_GetPrototype(ctx, s->target);
- ret = JS_CallFree(ctx, method, s->handler, 1, &s->target);
+ ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
if (JS_IsException(ret))
return ret;
if (JS_VALUE_GET_TAG(ret) != JS_TAG_NULL &&
@@ -44657,7 +46146,7 @@ static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj)
return -1;
if (JS_IsUndefined(method))
return JS_IsExtensible(ctx, s->target);
- ret = JS_CallFree(ctx, method, s->handler, 1, &s->target);
+ ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
if (JS_IsException(ret))
return -1;
res = JS_ToBoolFree(ctx, ret);
@@ -44683,7 +46172,7 @@ static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj)
return -1;
if (JS_IsUndefined(method))
return JS_PreventExtensions(ctx, s->target);
- ret = JS_CallFree(ctx, method, s->handler, 1, &s->target);
+ ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
if (JS_IsException(ret))
return -1;
res = JS_ToBoolFree(ctx, ret);
@@ -44803,9 +46292,9 @@ static int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom,
if (!s)
return -1;
if (JS_IsUndefined(method)) {
- return JS_SetPropertyGeneric(ctx, s->target, atom,
- JS_DupValue(ctx, value), receiver,
- flags);
+ return JS_SetPropertyInternal(ctx, s->target, atom,
+ JS_DupValue(ctx, value), receiver,
+ flags);
}
atom_val = JS_AtomToValue(ctx, atom);
if (JS_IsException(atom_val)) {
@@ -44871,17 +46360,17 @@ static JSValue js_create_desc(JSContext *ctx, JSValueConst val,
}
if (flags & JS_PROP_HAS_WRITABLE) {
JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
- JS_NewBool(ctx, (flags & JS_PROP_WRITABLE) != 0),
+ JS_NewBool(ctx, flags & JS_PROP_WRITABLE),
JS_PROP_C_W_E);
}
if (flags & JS_PROP_HAS_ENUMERABLE) {
JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
- JS_NewBool(ctx, (flags & JS_PROP_ENUMERABLE) != 0),
+ JS_NewBool(ctx, flags & JS_PROP_ENUMERABLE),
JS_PROP_C_W_E);
}
if (flags & JS_PROP_HAS_CONFIGURABLE) {
JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
- JS_NewBool(ctx, (flags & JS_PROP_CONFIGURABLE) != 0),
+ JS_NewBool(ctx, flags & JS_PROP_CONFIGURABLE),
JS_PROP_C_W_E);
}
return ret;
@@ -45167,7 +46656,7 @@ static int js_proxy_get_own_property_names(JSContext *ctx,
JS_VALUE_GET_OBJ(s->target),
JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK);
}
- prop_array = JS_CallFree(ctx, method, s->handler, 1, &s->target);
+ prop_array = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
if (JS_IsException(prop_array))
return -1;
tab = NULL;
@@ -45333,16 +46822,35 @@ static JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj,
return ret;
}
-static int js_proxy_isArray(JSContext *ctx, JSValueConst obj)
-{
- JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY);
- if (!s)
- return FALSE;
- if (s->is_revoked) {
- JS_ThrowTypeErrorRevokedProxy(ctx);
- return -1;
+/* `js_resolve_proxy`: resolve the proxy chain
+ `*pval` is updated with to ultimate proxy target
+ `throw_exception` controls whether exceptions are thown or not
+ - return -1 in case of error
+ - otherwise return 0
+ */
+static int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, BOOL throw_exception) {
+ int depth = 0;
+ JSObject *p;
+ JSProxyData *s;
+
+ while (JS_VALUE_GET_TAG(*pval) == JS_TAG_OBJECT) {
+ p = JS_VALUE_GET_OBJ(*pval);
+ if (p->class_id != JS_CLASS_PROXY)
+ break;
+ if (depth++ > 1000) {
+ if (throw_exception)
+ JS_ThrowStackOverflow(ctx);
+ return -1;
+ }
+ s = p->u.opaque;
+ if (s->is_revoked) {
+ if (throw_exception)
+ JS_ThrowTypeErrorRevokedProxy(ctx);
+ return -1;
+ }
+ *pval = s->target;
}
- return JS_IsArray(ctx, s->target);
+ return 0;
}
static const JSClassExoticMethods js_proxy_exotic_methods = {
@@ -45503,7 +47011,7 @@ static JSValue js_symbol_toString(JSContext *ctx, JSValueConst this_val,
if (JS_IsException(val))
return val;
/* XXX: use JS_ToStringInternal() with a flags */
- ret = js_string_constructor(ctx, JS_UNDEFINED, 1, &val);
+ ret = js_string_constructor(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val);
JS_FreeValue(ctx, val);
return ret;
}
@@ -45653,7 +47161,7 @@ static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target,
break;
}
if (is_set) {
- ret = JS_Call(ctx, adder, obj, 1, &item);
+ ret = JS_Call(ctx, adder, obj, 1, (JSValueConst *)&item);
if (JS_IsException(ret)) {
JS_FreeValue(ctx, item);
goto fail;
@@ -45737,7 +47245,7 @@ static uint32_t map_hash_key(JSContext *ctx, JSValueConst key)
h = (uintptr_t)JS_VALUE_GET_PTR(key) * 3163;
break;
case JS_TAG_INT:
- d = JS_VALUE_GET_INT(key) * 3163;
+ d = JS_VALUE_GET_INT(key);
goto hash_float64;
case JS_TAG_FLOAT64:
d = JS_VALUE_GET_FLOAT64(key);
@@ -45747,7 +47255,7 @@ static uint32_t map_hash_key(JSContext *ctx, JSValueConst key)
hash_float64:
u.d = d;
h = (u.u32[0] ^ u.u32[1]) * 3163;
- break;
+ return h ^= JS_TAG_FLOAT64;
default:
h = 0; /* XXX: bignum support */
break;
@@ -45971,7 +47479,7 @@ static JSValue js_map_has(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
key = map_normalize_key(ctx, argv[0]);
mr = map_find_record(ctx, s, key);
- return JS_NewBool(ctx, (mr != NULL));
+ return JS_NewBool(ctx, mr != NULL);
}
static JSValue js_map_delete(JSContext *ctx, JSValueConst this_val,
@@ -46063,6 +47571,123 @@ static JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val,
return JS_UNDEFINED;
}
+static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int is_map)
+{
+ JSValueConst cb, args[2];
+ JSValue res, iter, next, groups, key, v, prop;
+ JSAtom key_atom = JS_ATOM_NULL;
+ int64_t idx;
+ BOOL done;
+
+ // "is function?" check must be observed before argv[0] is accessed
+ cb = argv[1];
+ if (check_function(ctx, cb))
+ return JS_EXCEPTION;
+
+ iter = JS_GetIterator(ctx, argv[0], /*is_async*/FALSE);
+ if (JS_IsException(iter))
+ return JS_EXCEPTION;
+
+ key = JS_UNDEFINED;
+ key_atom = JS_ATOM_NULL;
+ v = JS_UNDEFINED;
+ prop = JS_UNDEFINED;
+ groups = JS_UNDEFINED;
+
+ next = JS_GetProperty(ctx, iter, JS_ATOM_next);
+ if (JS_IsException(next))
+ goto exception;
+
+ if (is_map) {
+ groups = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, 0);
+ } else {
+ groups = JS_NewObjectProto(ctx, JS_NULL);
+ }
+ if (JS_IsException(groups))
+ goto exception;
+
+ for (idx = 0; ; idx++) {
+ if (idx >= MAX_SAFE_INTEGER) {
+ JS_ThrowTypeError(ctx, "too many elements");
+ goto iterator_close_exception;
+ }
+ v = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
+ if (JS_IsException(v))
+ goto exception;
+ if (done)
+ break; // v is JS_UNDEFINED
+
+ args[0] = v;
+ args[1] = JS_NewInt64(ctx, idx);
+ key = JS_Call(ctx, cb, ctx->global_obj, 2, args);
+ if (JS_IsException(key))
+ goto iterator_close_exception;
+
+ if (is_map) {
+ prop = js_map_get(ctx, groups, 1, (JSValueConst *)&key, 0);
+ } else {
+ key_atom = JS_ValueToAtom(ctx, key);
+ JS_FreeValue(ctx, key);
+ key = JS_UNDEFINED;
+ if (key_atom == JS_ATOM_NULL)
+ goto iterator_close_exception;
+ prop = JS_GetProperty(ctx, groups, key_atom);
+ }
+ if (JS_IsException(prop))
+ goto exception;
+
+ if (JS_IsUndefined(prop)) {
+ prop = JS_NewArray(ctx);
+ if (JS_IsException(prop))
+ goto exception;
+ if (is_map) {
+ args[0] = key;
+ args[1] = prop;
+ res = js_map_set(ctx, groups, 2, args, 0);
+ if (JS_IsException(res))
+ goto exception;
+ JS_FreeValue(ctx, res);
+ } else {
+ prop = JS_DupValue(ctx, prop);
+ if (JS_DefinePropertyValue(ctx, groups, key_atom, prop,
+ JS_PROP_C_W_E) < 0) {
+ goto exception;
+ }
+ }
+ }
+ res = js_array_push(ctx, prop, 1, (JSValueConst *)&v, /*unshift*/0);
+ if (JS_IsException(res))
+ goto exception;
+ // res is an int64
+
+ JS_FreeValue(ctx, prop);
+ JS_FreeValue(ctx, key);
+ JS_FreeAtom(ctx, key_atom);
+ JS_FreeValue(ctx, v);
+ prop = JS_UNDEFINED;
+ key = JS_UNDEFINED;
+ key_atom = JS_ATOM_NULL;
+ v = JS_UNDEFINED;
+ }
+
+ JS_FreeValue(ctx, iter);
+ JS_FreeValue(ctx, next);
+ return groups;
+
+ iterator_close_exception:
+ JS_IteratorClose(ctx, iter, TRUE);
+ exception:
+ JS_FreeAtom(ctx, key_atom);
+ JS_FreeValue(ctx, prop);
+ JS_FreeValue(ctx, key);
+ JS_FreeValue(ctx, v);
+ JS_FreeValue(ctx, groups);
+ JS_FreeValue(ctx, iter);
+ JS_FreeValue(ctx, next);
+ return JS_EXCEPTION;
+}
+
static void js_map_finalizer(JSRuntime *rt, JSValue val)
{
JSObject *p;
@@ -46243,6 +47868,7 @@ static JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val,
}
static const JSCFunctionListEntry js_map_funcs[] = {
+ JS_CFUNC_MAGIC_DEF("groupBy", 2, js_object_groupBy, 1 ),
JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
};
@@ -46363,12 +47989,6 @@ static const JSCFunctionListEntry js_generator_proto_funcs[] = {
/* Promise */
-typedef enum JSPromiseStateEnum {
- JS_PROMISE_PENDING,
- JS_PROMISE_FULFILLED,
- JS_PROMISE_REJECTED,
-} JSPromiseStateEnum;
-
typedef struct JSPromiseData {
JSPromiseStateEnum promise_state;
/* 0=fulfill, 1=reject, list of JSPromiseReactionData.link */
@@ -46393,6 +48013,22 @@ typedef struct JSPromiseReactionData {
JSValue handler;
} JSPromiseReactionData;
+JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise)
+{
+ JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
+ if (!s)
+ return -1;
+ return s->promise_state;
+}
+
+JSValue JS_PromiseResult(JSContext *ctx, JSValue promise)
+{
+ JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
+ if (!s)
+ return JS_UNDEFINED;
+ return JS_DupValue(ctx, s->promise_result);
+}
+
static int js_create_resolving_functions(JSContext *ctx, JSValue *args,
JSValueConst promise);
@@ -46438,7 +48074,7 @@ static JSValue promise_reaction_job(JSContext *ctx, int argc,
functions */
if (!JS_IsUndefined(func)) {
res2 = JS_Call(ctx, func, JS_UNDEFINED,
- 1, &res);
+ 1, (JSValueConst *)&res);
} else {
res2 = JS_UNDEFINED;
}
@@ -46521,7 +48157,7 @@ static JSValue js_promise_resolve_thenable_job(JSContext *ctx,
res = JS_Call(ctx, then, thenable, 2, (JSValueConst *)args);
if (JS_IsException(res)) {
JSValue error = JS_GetException(ctx);
- res = JS_Call(ctx, args[1], JS_UNDEFINED, 1, &error);
+ res = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);
JS_FreeValue(ctx, error);
}
JS_FreeValue(ctx, args[0]);
@@ -46721,7 +48357,7 @@ static JSValue js_promise_constructor(JSContext *ctx, JSValueConst new_target,
if (JS_IsException(ret)) {
JSValue ret2, error;
error = JS_GetException(ctx);
- ret2 = JS_Call(ctx, args[1], JS_UNDEFINED, 1, &error);
+ ret2 = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);
JS_FreeValue(ctx, error);
if (JS_IsException(ret2))
goto fail1;
@@ -46778,10 +48414,10 @@ static JSValue js_new_promise_capability(JSContext *ctx,
if (JS_IsUndefined(ctor)) {
result_promise = js_promise_constructor(ctx, ctor, 1,
- &executor);
+ (JSValueConst *)&executor);
} else {
result_promise = JS_CallConstructor(ctx, ctor, 1,
- &executor);
+ (JSValueConst *)&executor);
}
if (JS_IsException(result_promise))
goto fail;
@@ -46838,17 +48474,14 @@ static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
return result_promise;
}
-#if 0
-static JSValue js_promise___newPromiseCapability(JSContext *ctx,
- JSValueConst this_val,
- int argc, JSValueConst *argv)
+static JSValue js_promise_withResolvers(JSContext *ctx,
+ JSValueConst this_val,
+ int argc, JSValueConst *argv)
{
JSValue result_promise, resolving_funcs[2], obj;
- JSValueConst ctor;
- ctor = argv[0];
- if (!JS_IsObject(ctor))
+ if (!JS_IsObject(this_val))
return JS_ThrowTypeErrorNotAnObject(ctx);
- result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor);
+ result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
if (JS_IsException(result_promise))
return result_promise;
obj = JS_NewObject(ctx);
@@ -46863,9 +48496,8 @@ static JSValue js_promise___newPromiseCapability(JSContext *ctx,
JS_DefinePropertyValue(ctx, obj, JS_ATOM_reject, resolving_funcs[1], JS_PROP_C_W_E);
return obj;
}
-#endif
-static warn_unused int remainingElementsCount_add(JSContext *ctx,
+static __exception int remainingElementsCount_add(JSContext *ctx,
JSValueConst resolve_element_env,
int addend)
{
@@ -46946,10 +48578,10 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx,
error = js_aggregate_error_constructor(ctx, values);
if (JS_IsException(error))
return JS_EXCEPTION;
- ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, &error);
+ ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&error);
JS_FreeValue(ctx, error);
} else {
- ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, &values);
+ ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&values);
}
if (JS_IsException(ret))
return ret;
@@ -46985,7 +48617,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
fail_reject:
error = JS_GetException(ctx);
ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
- &error);
+ (JSValueConst *)&error);
JS_FreeValue(ctx, error);
if (JS_IsException(ret))
goto fail;
@@ -47016,7 +48648,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
if (done)
break;
next_promise = JS_Call(ctx, promise_resolve,
- this_val, 1, &item);
+ this_val, 1, (JSValueConst *)&item);
JS_FreeValue(ctx, item);
if (JS_IsException(next_promise)) {
fail_reject1:
@@ -47084,7 +48716,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
values = error;
}
ret = JS_Call(ctx, resolving_funcs[is_promise_any], JS_UNDEFINED,
- 1, &values);
+ 1, (JSValueConst *)&values);
if (check_exception_free(ctx, ret))
goto fail_reject;
}
@@ -47127,7 +48759,7 @@ static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val,
fail_reject:
error = JS_GetException(ctx);
ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
- &error);
+ (JSValueConst *)&error);
JS_FreeValue(ctx, error);
if (JS_IsException(ret))
goto fail;
@@ -47146,7 +48778,7 @@ static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val,
if (done)
break;
next_promise = JS_Call(ctx, promise_resolve,
- this_val, 1, &item);
+ this_val, 1, (JSValueConst *)&item);
JS_FreeValue(ctx, item);
if (JS_IsException(next_promise)) {
fail_reject1:
@@ -47173,7 +48805,7 @@ static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val,
goto done;
}
-static warn_unused int perform_promise_then(JSContext *ctx,
+static __exception int perform_promise_then(JSContext *ctx,
JSValueConst promise,
JSValueConst *resolve_reject,
JSValueConst *cap_resolving_funcs)
@@ -47291,7 +48923,7 @@ static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_va
res = JS_Call(ctx, onFinally, JS_UNDEFINED, 0, NULL);
if (JS_IsException(res))
return res;
- promise = js_promise_resolve(ctx, ctor, 1, &res, 0);
+ promise = js_promise_resolve(ctx, ctor, 1, (JSValueConst *)&res, 0);
JS_FreeValue(ctx, res);
if (JS_IsException(promise))
return promise;
@@ -47306,7 +48938,7 @@ static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_va
JS_FreeValue(ctx, promise);
return then_func;
}
- ret = JS_InvokeFree(ctx, promise, JS_ATOM_then, 1, &then_func);
+ ret = JS_InvokeFree(ctx, promise, JS_ATOM_then, 1, (JSValueConst *)&then_func);
JS_FreeValue(ctx, then_func);
return ret;
}
@@ -47353,7 +48985,7 @@ static const JSCFunctionListEntry js_promise_funcs[] = {
JS_CFUNC_MAGIC_DEF("allSettled", 1, js_promise_all, PROMISE_MAGIC_allSettled ),
JS_CFUNC_MAGIC_DEF("any", 1, js_promise_all, PROMISE_MAGIC_any ),
JS_CFUNC_DEF("race", 1, js_promise_race ),
- //JS_CFUNC_DEF("__newPromiseCapability", 1, js_promise___newPromiseCapability ),
+ JS_CFUNC_DEF("withResolvers", 0, js_promise_withResolvers ),
JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL),
};
@@ -47506,7 +49138,7 @@ static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst thi
is_reject = 1;
done_resolve:
res2 = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED,
- 1, &err);
+ 1, (JSValueConst *)&err);
JS_FreeValue(ctx, err);
JS_FreeValue(ctx, res2);
JS_FreeValue(ctx, resolving_funcs[0]);
@@ -47518,7 +49150,7 @@ static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst thi
int res;
value_wrapper_promise = js_promise_resolve(ctx, ctx->promise_ctor,
- 1, &value, 0);
+ 1, (JSValueConst *)&value, 0);
if (JS_IsException(value_wrapper_promise)) {
JS_FreeValue(ctx, value);
goto reject;
@@ -47766,8 +49398,7 @@ static JSValue js_global_decodeURI(JSContext *ctx, JSValueConst this_val,
}
c = (c << 6) | (c1 & 0x3f);
}
- if (c < c_min || c > 0x10FFFF ||
- (c >= 0xd800 && c < 0xe000)) {
+ if (c < c_min || c > 0x10FFFF || is_surrogate(c)) {
js_throw_URIError(ctx, "malformed UTF-8");
goto fail;
}
@@ -47842,21 +49473,21 @@ static JSValue js_global_encodeURI(JSContext *ctx, JSValueConst this_val,
if (isURIUnescaped(c, isComponent)) {
string_buffer_putc16(b, c);
} else {
- if (c >= 0xdc00 && c <= 0xdfff) {
+ if (is_lo_surrogate(c)) {
js_throw_URIError(ctx, "invalid character");
goto fail;
- } else if (c >= 0xd800 && c <= 0xdbff) {
+ } else if (is_hi_surrogate(c)) {
if (k >= p->len) {
js_throw_URIError(ctx, "expecting surrogate pair");
goto fail;
}
c1 = string_get(p, k);
k++;
- if (c1 < 0xdc00 || c1 > 0xdfff) {
+ if (!is_lo_surrogate(c1)) {
js_throw_URIError(ctx, "expecting surrogate pair");
goto fail;
}
- c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
+ c = from_surrogate(c, c1);
}
if (c < 0x80) {
encodeURI_hex(b, c);
@@ -47964,12 +49595,7 @@ static const JSCFunctionListEntry js_global_funcs[] = {
JS_PROP_DOUBLE_DEF("Infinity", 1.0 / 0.0, 0 ),
JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ),
JS_PROP_UNDEFINED_DEF("undefined", 0 ),
-
- /* for the 'Date' implementation */
- JS_CFUNC_DEF("__date_clock", 0, js___date_clock ),
- //JS_CFUNC_DEF("__date_now", 0, js___date_now ),
- //JS_CFUNC_DEF("__date_getTimezoneOffset", 1, js___date_getTimezoneOffset ),
- //JS_CFUNC_DEF("__date_create", 3, js___date_create ),
+ JS_PROP_STRING_DEF("[Symbol.toStringTag]", "global", JS_PROP_CONFIGURABLE ),
};
/* Date */
@@ -47989,7 +49615,7 @@ static int64_t floor_div(int64_t a, int64_t b) {
static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv);
-static warn_unused int JS_ThisTimeValue(JSContext *ctx, double *valp, JSValueConst this_val)
+static __exception int JS_ThisTimeValue(JSContext *ctx, double *valp, JSValueConst this_val)
{
if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
JSObject *p = JS_VALUE_GET_OBJ(this_val);
@@ -48049,8 +49675,8 @@ static int const month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
static char const month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
static char const day_names[] = "SunMonTueWedThuFriSat";
-static warn_unused int get_date_fields(JSContext *ctx, JSValueConst obj,
- double fields[9], int is_local, int force)
+static __exception int get_date_fields(JSContext *ctx, JSValueConst obj,
+ double fields[minimum_length(9)], int is_local, int force)
{
double dval;
int64_t d, days, wd, y, i, md, h, m, s, ms, tz = 0;
@@ -48063,7 +49689,7 @@ static warn_unused int get_date_fields(JSContext *ctx, JSValueConst obj,
return FALSE; /* NaN */
d = 0; /* initialize all fields to 0 */
} else {
- d = dval;
+ d = dval; /* assuming -8.64e15 <= dval <= -8.64e15 */
if (is_local) {
tz = -getTimezoneOffset(d);
d += tz * 60000;
@@ -48109,33 +49735,63 @@ static double time_clip(double t) {
return NAN;
}
-/* The spec mandates the use of 'double' and it fixes the order
+/* The spec mandates the use of 'double' and it specifies the order
of the operations */
-static double set_date_fields(const double fields[], int is_local) {
- int64_t y;
- double days, d, h, m1;
- int i, m, md;
-
- m1 = fields[1];
- m = fmod(m1, 12);
- if (m < 0)
- m += 12;
- y = (int64_t)(fields[0] + floor(m1 / 12));
- days = days_from_year(y);
-
- for(i = 0; i < m; i++) {
- md = month_days[i];
+static double set_date_fields(double fields[minimum_length(7)], int is_local) {
+ double y, m, dt, ym, mn, day, h, s, milli, time, tv;
+ int yi, mi, i;
+ int64_t days;
+ volatile double temp; /* enforce evaluation order */
+
+ /* emulate 21.4.1.15 MakeDay ( year, month, date ) */
+ y = fields[0];
+ m = fields[1];
+ dt = fields[2];
+ ym = y + floor(m / 12);
+ mn = fmod(m, 12);
+ if (mn < 0)
+ mn += 12;
+ if (ym < -271821 || ym > 275760)
+ return NAN;
+
+ yi = ym;
+ mi = mn;
+ days = days_from_year(yi);
+ for(i = 0; i < mi; i++) {
+ days += month_days[i];
if (i == 1)
- md += days_in_year(y) - 365;
- days += md;
+ days += days_in_year(yi) - 365;
}
- days += fields[2] - 1;
- h = fields[3] * 3600000 + fields[4] * 60000 +
- fields[5] * 1000 + fields[6];
- d = days * 86400000 + h;
- if (is_local)
- d += getTimezoneOffset(d) * 60000;
- return time_clip(d);
+ day = days + dt - 1;
+
+ /* emulate 21.4.1.14 MakeTime ( hour, min, sec, ms ) */
+ h = fields[3];
+ m = fields[4];
+ s = fields[5];
+ milli = fields[6];
+ /* Use a volatile intermediary variable to ensure order of evaluation
+ * as specified in ECMA. This fixes a test262 error on
+ * test262/test/built-ins/Date/UTC/fp-evaluation-order.js.
+ * Without the volatile qualifier, the compile can generate code
+ * that performs the computation in a different order or with instructions
+ * that produce a different result such as FMA (float multiply and add).
+ */
+ time = h * 3600000;
+ time += (temp = m * 60000);
+ time += (temp = s * 1000);
+ time += milli;
+
+ /* emulate 21.4.1.16 MakeDate ( day, time ) */
+ tv = (temp = day * 86400000) + time; /* prevent generation of FMA */
+ if (!isfinite(tv))
+ return NAN;
+
+ /* adjust for local time and clip */
+ if (is_local) {
+ int64_t ti = tv < INT64_MIN ? INT64_MIN : tv >= 0x1p63 ? INT64_MAX : (int64_t)tv;
+ tv += getTimezoneOffset(ti) * 60000;
+ }
+ return time_clip(tv);
}
static JSValue get_date_field(JSContext *ctx, JSValueConst this_val,
@@ -48175,20 +49831,19 @@ static JSValue set_date_field(JSContext *ctx, JSValueConst this_val,
res = get_date_fields(ctx, this_val, fields, is_local, first_field == 0);
if (res < 0)
return JS_EXCEPTION;
- if (res && argc > 0) {
- n = end_field - first_field;
- if (argc < n)
- n = argc;
- for(i = 0; i < n; i++) {
- if (JS_ToFloat64(ctx, &a, argv[i]))
- return JS_EXCEPTION;
- if (!isfinite(a))
- goto done;
- fields[first_field + i] = trunc(a);
- }
- d = set_date_fields(fields, is_local);
+
+ // Argument coercion is observable and must be done unconditionally.
+ n = min_int(argc, end_field - first_field);
+ for(i = 0; i < n; i++) {
+ if (JS_ToFloat64(ctx, &a, argv[i]))
+ return JS_EXCEPTION;
+ if (!isfinite(a))
+ res = FALSE;
+ fields[first_field + i] = trunc(a);
}
-done:
+ if (res && argc > 0)
+ d = set_date_fields(fields, is_local);
+
return JS_SetThisTimeValue(ctx, this_val, d);
}
@@ -48298,7 +49953,7 @@ static JSValue get_date_string(JSContext *ctx, JSValueConst this_val,
break;
case 3:
pos += snprintf(buf + pos, sizeof(buf) - pos,
- "%02d:%02d:%02d %cM", (h + 1) % 12 - 1, m, s,
+ "%02d:%02d:%02d %cM", (h + 11) % 12 + 1, m, s,
(h < 12) ? 'A' : 'P');
break;
}
@@ -48313,7 +49968,7 @@ static int64_t date_now(void) {
GetSystemTime(&st);
int64_t d;
SystemTimeToFileTime(&st, (FILETIME *) &d);
- return d /= 10000;
+ return (d - 116444736000000000ULL) / 10000;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
@@ -48349,7 +50004,7 @@ static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target,
}
v = JS_ToPrimitive(ctx, argv[0], HINT_NONE);
if (JS_IsString(v)) {
- dv = js_Date_parse(ctx, JS_UNDEFINED, 1, &v);
+ dv = js_Date_parse(ctx, JS_UNDEFINED, 1, (JSValueConst *)&v);
JS_FreeValue(ctx, v);
if (JS_IsException(dv))
return JS_EXCEPTION;
@@ -48422,142 +50077,418 @@ static JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val,
return JS_NewFloat64(ctx, set_date_fields(fields, 0));
}
-static void string_skip_spaces(JSString *sp, int *pp) {
- while (*pp < sp->len && string_get(sp, *pp) == ' ')
+/* Date string parsing */
+
+static BOOL string_skip_char(const uint8_t *sp, int *pp, int c) {
+ if (sp[*pp] == c) {
*pp += 1;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
}
-static void string_skip_non_spaces(JSString *sp, int *pp) {
- while (*pp < sp->len && string_get(sp, *pp) != ' ')
+/* skip spaces, update offset, return next char */
+static int string_skip_spaces(const uint8_t *sp, int *pp) {
+ int c;
+ while ((c = sp[*pp]) == ' ')
+ *pp += 1;
+ return c;
+}
+
+/* skip dashes dots and commas */
+static int string_skip_separators(const uint8_t *sp, int *pp) {
+ int c;
+ while ((c = sp[*pp]) == '-' || c == '/' || c == '.' || c == ',')
+ *pp += 1;
+ return c;
+}
+
+/* skip a word, stop on spaces, digits and separators, update offset */
+static int string_skip_until(const uint8_t *sp, int *pp, const char *stoplist) {
+ int c;
+ while (!strchr(stoplist, c = sp[*pp]))
*pp += 1;
+ return c;
}
-/* parse a numeric field with an optional sign if accept_sign is TRUE */
-static int string_get_digits(JSString *sp, int *pp, int64_t *pval) {
- int64_t v = 0;
+/* parse a numeric field (max_digits = 0 -> no maximum) */
+static BOOL string_get_digits(const uint8_t *sp, int *pp, int *pval,
+ int min_digits, int max_digits)
+{
+ int v = 0;
int c, p = *pp, p_start;
- if (p >= sp->len)
- return -1;
p_start = p;
- while (p < sp->len) {
- c = string_get(sp, p);
- if (!(c >= '0' && c <= '9')) {
- if (p == p_start)
- return -1;
- else
- break;
- }
+ while ((c = sp[p]) >= '0' && c <= '9') {
v = v * 10 + c - '0';
p++;
+ if (p - p_start == max_digits)
+ break;
}
+ if (p - p_start < min_digits)
+ return FALSE;
*pval = v;
*pp = p;
- return 0;
+ return TRUE;
}
-static int string_get_signed_digits(JSString *sp, int *pp, int64_t *pval) {
- int res, sgn, p = *pp;
-
- if (p >= sp->len)
- return -1;
+static BOOL string_get_milliseconds(const uint8_t *sp, int *pp, int *pval) {
+ /* parse optional fractional part as milliseconds and truncate. */
+ /* spec does not indicate which rounding should be used */
+ int mul = 100, ms = 0, c, p_start, p = *pp;
- sgn = string_get(sp, p);
- if (sgn == '-' || sgn == '+')
+ c = sp[p];
+ if (c == '.' || c == ',') {
p++;
+ p_start = p;
+ while ((c = sp[p]) >= '0' && c <= '9') {
+ ms += (c - '0') * mul;
+ mul /= 10;
+ p++;
+ if (p - p_start == 9)
+ break;
+ }
+ if (p > p_start) {
+ /* only consume the separator if digits are present */
+ *pval = ms;
+ *pp = p;
+ }
+ }
+ return TRUE;
+}
- res = string_get_digits(sp, &p, pval);
- if (res == 0 && sgn == '-')
- *pval = -*pval;
- *pp = p;
- return res;
+static uint8_t upper_ascii(uint8_t c) {
+ return c >= 'a' && c <= 'z' ? c - 'a' + 'A' : c;
}
-/* parse a fixed width numeric field */
-static int string_get_fixed_width_digits(JSString *sp, int *pp, int n, int64_t *pval) {
- int64_t v = 0;
- int i, c, p = *pp;
+static BOOL string_get_tzoffset(const uint8_t *sp, int *pp, int *tzp, BOOL strict) {
+ int tz = 0, sgn, hh, mm, p = *pp;
- for(i = 0; i < n; i++) {
- if (p >= sp->len)
- return -1;
- c = string_get(sp, p);
- if (!(c >= '0' && c <= '9'))
- return -1;
- v = v * 10 + c - '0';
- p++;
+ sgn = sp[p++];
+ if (sgn == '+' || sgn == '-') {
+ int n = p;
+ if (!string_get_digits(sp, &p, &hh, 1, 9))
+ return FALSE;
+ n = p - n;
+ if (strict && n != 2 && n != 4)
+ return FALSE;
+ while (n > 4) {
+ n -= 2;
+ hh /= 100;
+ }
+ if (n > 2) {
+ mm = hh % 100;
+ hh = hh / 100;
+ } else {
+ mm = 0;
+ if (string_skip_char(sp, &p, ':') /* optional separator */
+ && !string_get_digits(sp, &p, &mm, 2, 2))
+ return FALSE;
+ }
+ if (hh > 23 || mm > 59)
+ return FALSE;
+ tz = hh * 60 + mm;
+ if (sgn != '+')
+ tz = -tz;
+ } else
+ if (sgn != 'Z') {
+ return FALSE;
}
- *pval = v;
*pp = p;
- return 0;
+ *tzp = tz;
+ return TRUE;
}
-static int string_get_milliseconds(JSString *sp, int *pp, int64_t *pval) {
- /* parse milliseconds as a fractional part, round to nearest */
- /* XXX: the spec does not indicate which rounding should be used */
- int mul = 1000, ms = 0, p = *pp, c, p_start;
- if (p >= sp->len)
- return -1;
- p_start = p;
- while (p < sp->len) {
- c = string_get(sp, p);
- if (!(c >= '0' && c <= '9')) {
- if (p == p_start)
- return -1;
- else
- break;
- }
- if (mul == 1 && c >= '5')
- ms += 1;
- ms += (c - '0') * (mul /= 10);
+static BOOL string_match(const uint8_t *sp, int *pp, const char *s) {
+ int p = *pp;
+ while (*s != '\0') {
+ if (upper_ascii(sp[p]) != upper_ascii(*s++))
+ return FALSE;
p++;
}
- *pval = ms;
*pp = p;
- return 0;
+ return TRUE;
}
-
-static int find_abbrev(JSString *sp, int p, const char *list, int count) {
+static int find_abbrev(const uint8_t *sp, int p, const char *list, int count) {
int n, i;
- if (p + 3 <= sp->len) {
- for (n = 0; n < count; n++) {
- for (i = 0; i < 3; i++) {
- if (string_get(sp, p + i) != month_names[n * 3 + i])
- goto next;
- }
- return n;
- next:;
+ for (n = 0; n < count; n++) {
+ for (i = 0;; i++) {
+ if (upper_ascii(sp[p + i]) != upper_ascii(list[n * 3 + i]))
+ break;
+ if (i == 2)
+ return n;
}
}
return -1;
}
-static int string_get_month(JSString *sp, int *pp, int64_t *pval) {
+static BOOL string_get_month(const uint8_t *sp, int *pp, int *pval) {
int n;
- string_skip_spaces(sp, pp);
n = find_abbrev(sp, *pp, month_names, 12);
if (n < 0)
- return -1;
+ return FALSE;
- *pval = n;
+ *pval = n + 1;
*pp += 3;
- return 0;
+ return TRUE;
+}
+
+/* parse toISOString format */
+static BOOL js_date_parse_isostring(const uint8_t *sp, int fields[9], BOOL *is_local) {
+ int sgn, i, p = 0;
+
+ /* initialize fields to the beginning of the Epoch */
+ for (i = 0; i < 9; i++) {
+ fields[i] = (i == 2);
+ }
+ *is_local = FALSE;
+
+ /* year is either yyyy digits or [+-]yyyyyy */
+ sgn = sp[p];
+ if (sgn == '-' || sgn == '+') {
+ p++;
+ if (!string_get_digits(sp, &p, &fields[0], 6, 6))
+ return FALSE;
+ if (sgn == '-') {
+ if (fields[0] == 0)
+ return FALSE; // reject -000000
+ fields[0] = -fields[0];
+ }
+ } else {
+ if (!string_get_digits(sp, &p, &fields[0], 4, 4))
+ return FALSE;
+ }
+ if (string_skip_char(sp, &p, '-')) {
+ if (!string_get_digits(sp, &p, &fields[1], 2, 2)) /* month */
+ return FALSE;
+ if (fields[1] < 1)
+ return FALSE;
+ fields[1] -= 1;
+ if (string_skip_char(sp, &p, '-')) {
+ if (!string_get_digits(sp, &p, &fields[2], 2, 2)) /* day */
+ return FALSE;
+ if (fields[2] < 1)
+ return FALSE;
+ }
+ }
+ if (string_skip_char(sp, &p, 'T')) {
+ *is_local = TRUE;
+ if (!string_get_digits(sp, &p, &fields[3], 2, 2) /* hour */
+ || !string_skip_char(sp, &p, ':')
+ || !string_get_digits(sp, &p, &fields[4], 2, 2)) { /* minute */
+ fields[3] = 100; // reject unconditionally
+ return TRUE;
+ }
+ if (string_skip_char(sp, &p, ':')) {
+ if (!string_get_digits(sp, &p, &fields[5], 2, 2)) /* second */
+ return FALSE;
+ string_get_milliseconds(sp, &p, &fields[6]);
+ }
+ }
+ /* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */
+ if (sp[p]) {
+ *is_local = FALSE;
+ if (!string_get_tzoffset(sp, &p, &fields[8], TRUE))
+ return FALSE;
+ }
+ /* error if extraneous characters */
+ return sp[p] == '\0';
+}
+
+static struct {
+ char name[6];
+ int16_t offset;
+} const js_tzabbr[] = {
+ { "GMT", 0 }, // Greenwich Mean Time
+ { "UTC", 0 }, // Coordinated Universal Time
+ { "UT", 0 }, // Universal Time
+ { "Z", 0 }, // Zulu Time
+ { "EDT", -4 * 60 }, // Eastern Daylight Time
+ { "EST", -5 * 60 }, // Eastern Standard Time
+ { "CDT", -5 * 60 }, // Central Daylight Time
+ { "CST", -6 * 60 }, // Central Standard Time
+ { "MDT", -6 * 60 }, // Mountain Daylight Time
+ { "MST", -7 * 60 }, // Mountain Standard Time
+ { "PDT", -7 * 60 }, // Pacific Daylight Time
+ { "PST", -8 * 60 }, // Pacific Standard Time
+ { "WET", +0 * 60 }, // Western European Time
+ { "WEST", +1 * 60 }, // Western European Summer Time
+ { "CET", +1 * 60 }, // Central European Time
+ { "CEST", +2 * 60 }, // Central European Summer Time
+ { "EET", +2 * 60 }, // Eastern European Time
+ { "EEST", +3 * 60 }, // Eastern European Summer Time
+};
+
+static BOOL string_get_tzabbr(const uint8_t *sp, int *pp, int *offset) {
+ for (size_t i = 0; i < countof(js_tzabbr); i++) {
+ if (string_match(sp, pp, js_tzabbr[i].name)) {
+ *offset = js_tzabbr[i].offset;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/* parse toString, toUTCString and other formats */
+static BOOL js_date_parse_otherstring(const uint8_t *sp,
+ int fields[minimum_length(9)],
+ BOOL *is_local) {
+ int c, i, val, p = 0, p_start;
+ int num[3];
+ BOOL has_year = FALSE;
+ BOOL has_mon = FALSE;
+ BOOL has_time = FALSE;
+ int num_index = 0;
+
+ /* initialize fields to the beginning of 2001-01-01 */
+ fields[0] = 2001;
+ fields[1] = 1;
+ fields[2] = 1;
+ for (i = 3; i < 9; i++) {
+ fields[i] = 0;
+ }
+ *is_local = TRUE;
+
+ while (string_skip_spaces(sp, &p)) {
+ p_start = p;
+ if ((c = sp[p]) == '+' || c == '-') {
+ if (has_time && string_get_tzoffset(sp, &p, &fields[8], FALSE)) {
+ *is_local = FALSE;
+ } else {
+ p++;
+ if (string_get_digits(sp, &p, &val, 1, 9)) {
+ if (c == '-') {
+ if (val == 0)
+ return FALSE;
+ val = -val;
+ }
+ fields[0] = val;
+ has_year = TRUE;
+ }
+ }
+ } else
+ if (string_get_digits(sp, &p, &val, 1, 9)) {
+ if (string_skip_char(sp, &p, ':')) {
+ /* time part */
+ fields[3] = val;
+ if (!string_get_digits(sp, &p, &fields[4], 1, 2))
+ return FALSE;
+ if (string_skip_char(sp, &p, ':')) {
+ if (!string_get_digits(sp, &p, &fields[5], 1, 2))
+ return FALSE;
+ string_get_milliseconds(sp, &p, &fields[6]);
+ }
+ has_time = TRUE;
+ } else {
+ if (p - p_start > 2) {
+ fields[0] = val;
+ has_year = TRUE;
+ } else
+ if (val < 1 || val > 31) {
+ fields[0] = val + (val < 100) * 1900 + (val < 50) * 100;
+ has_year = TRUE;
+ } else {
+ if (num_index == 3)
+ return FALSE;
+ num[num_index++] = val;
+ }
+ }
+ } else
+ if (string_get_month(sp, &p, &fields[1])) {
+ has_mon = TRUE;
+ string_skip_until(sp, &p, "0123456789 -/(");
+ } else
+ if (has_time && string_match(sp, &p, "PM")) {
+ if (fields[3] < 12)
+ fields[3] += 12;
+ continue;
+ } else
+ if (has_time && string_match(sp, &p, "AM")) {
+ if (fields[3] == 12)
+ fields[3] -= 12;
+ continue;
+ } else
+ if (string_get_tzabbr(sp, &p, &fields[8])) {
+ *is_local = FALSE;
+ continue;
+ } else
+ if (c == '(') { /* skip parenthesized phrase */
+ int level = 0;
+ while ((c = sp[p]) != '\0') {
+ p++;
+ level += (c == '(');
+ level -= (c == ')');
+ if (!level)
+ break;
+ }
+ if (level > 0)
+ return FALSE;
+ } else
+ if (c == ')') {
+ return FALSE;
+ } else {
+ if (has_year + has_mon + has_time + num_index)
+ return FALSE;
+ /* skip a word */
+ string_skip_until(sp, &p, " -/(");
+ }
+ string_skip_separators(sp, &p);
+ }
+ if (num_index + has_year + has_mon > 3)
+ return FALSE;
+
+ switch (num_index) {
+ case 0:
+ if (!has_year)
+ return FALSE;
+ break;
+ case 1:
+ if (has_mon)
+ fields[2] = num[0];
+ else
+ fields[1] = num[0];
+ break;
+ case 2:
+ if (has_year) {
+ fields[1] = num[0];
+ fields[2] = num[1];
+ } else
+ if (has_mon) {
+ fields[0] = num[1] + (num[1] < 100) * 1900 + (num[1] < 50) * 100;
+ fields[2] = num[0];
+ } else {
+ fields[1] = num[0];
+ fields[2] = num[1];
+ }
+ break;
+ case 3:
+ fields[0] = num[2] + (num[2] < 100) * 1900 + (num[2] < 50) * 100;
+ fields[1] = num[0];
+ fields[2] = num[1];
+ break;
+ default:
+ return FALSE;
+ }
+ if (fields[1] < 1 || fields[2] < 1)
+ return FALSE;
+ fields[1] -= 1;
+ return TRUE;
}
static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
- // parse(s)
JSValue s, rv;
- int64_t fields[] = { 0, 1, 1, 0, 0, 0, 0 };
- double fields1[7];
- int64_t tz, hh, mm;
+ int fields[9];
+ double fields1[9];
double d;
- int p, i, c, sgn, l;
+ int i, c;
JSString *sp;
+ uint8_t buf[128];
BOOL is_local;
rv = JS_NAN;
@@ -48567,145 +50498,33 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
sp = JS_VALUE_GET_STRING(s);
- p = 0;
- if (p < sp->len && (((c = string_get(sp, p)) >= '0' && c <= '9') || c == '+' || c == '-')) {
- /* ISO format */
- /* year field can be negative */
- if (string_get_signed_digits(sp, &p, &fields[0]))
- goto done;
-
- for (i = 1; i < 7; i++) {
- if (p >= sp->len)
- break;
- switch(i) {
- case 1:
- case 2:
- c = '-';
- break;
- case 3:
- c = 'T';
- break;
- case 4:
- case 5:
- c = ':';
- break;
- case 6:
- c = '.';
- break;
- }
- if (string_get(sp, p) != c)
- break;
- p++;
- if (i == 6) {
- if (string_get_milliseconds(sp, &p, &fields[i]))
- goto done;
- } else {
- if (string_get_digits(sp, &p, &fields[i]))
- goto done;
- }
- }
- /* no time: UTC by default */
- is_local = (i > 3);
- fields[1] -= 1;
-
- /* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */
- tz = 0;
- if (p < sp->len) {
- sgn = string_get(sp, p);
- if (sgn == '+' || sgn == '-') {
- p++;
- l = sp->len - p;
- if (l != 4 && l != 5)
- goto done;
- if (string_get_fixed_width_digits(sp, &p, 2, &hh))
- goto done;
- if (l == 5) {
- if (string_get(sp, p) != ':')
- goto done;
- p++;
- }
- if (string_get_fixed_width_digits(sp, &p, 2, &mm))
- goto done;
- tz = hh * 60 + mm;
- if (sgn == '-')
- tz = -tz;
- is_local = FALSE;
- } else if (sgn == 'Z') {
- p++;
- is_local = FALSE;
- } else {
- goto done;
- }
- /* error if extraneous characters */
- if (p != sp->len)
- goto done;
- }
- } else {
- /* toString or toUTCString format */
- /* skip the day of the week */
- string_skip_non_spaces(sp, &p);
- string_skip_spaces(sp, &p);
- if (p >= sp->len)
- goto done;
- c = string_get(sp, p);
- if (c >= '0' && c <= '9') {
- /* day of month first */
- if (string_get_digits(sp, &p, &fields[2]))
- goto done;
- if (string_get_month(sp, &p, &fields[1]))
- goto done;
- } else {
- /* month first */
- if (string_get_month(sp, &p, &fields[1]))
- goto done;
- string_skip_spaces(sp, &p);
- if (string_get_digits(sp, &p, &fields[2]))
- goto done;
- }
- /* year */
- string_skip_spaces(sp, &p);
- if (string_get_signed_digits(sp, &p, &fields[0]))
- goto done;
-
- /* hour, min, seconds */
- string_skip_spaces(sp, &p);
- for(i = 0; i < 3; i++) {
- if (i == 1 || i == 2) {
- if (p >= sp->len)
- goto done;
- if (string_get(sp, p) != ':')
- goto done;
- p++;
- }
- if (string_get_digits(sp, &p, &fields[3 + i]))
- goto done;
- }
- // XXX: parse optional milliseconds?
-
- /* parse the time zone offset if present: [+-]HHmm */
- is_local = FALSE;
- tz = 0;
- for (tz = 0; p < sp->len; p++) {
- sgn = string_get(sp, p);
- if (sgn == '+' || sgn == '-') {
- p++;
- if (string_get_fixed_width_digits(sp, &p, 2, &hh))
- goto done;
- if (string_get_fixed_width_digits(sp, &p, 2, &mm))
- goto done;
- tz = hh * 60 + mm;
- if (sgn == '-')
- tz = -tz;
- break;
- }
+ /* convert the string as a byte array */
+ for (i = 0; i < sp->len && i < (int)countof(buf) - 1; i++) {
+ c = string_get(sp, i);
+ if (c > 255)
+ c = (c == 0x2212) ? '-' : 'x';
+ buf[i] = c;
+ }
+ buf[i] = '\0';
+ if (js_date_parse_isostring(buf, fields, &is_local)
+ || js_date_parse_otherstring(buf, fields, &is_local)) {
+ static int const field_max[6] = { 0, 11, 31, 24, 59, 59 };
+ BOOL valid = TRUE;
+ /* check field maximum values */
+ for (i = 1; i < 6; i++) {
+ if (fields[i] > field_max[i])
+ valid = FALSE;
+ }
+ /* special case 24:00:00.000 */
+ if (fields[3] == 24 && (fields[4] | fields[5] | fields[6]))
+ valid = FALSE;
+ if (valid) {
+ for(i = 0; i < 7; i++)
+ fields1[i] = fields[i];
+ d = set_date_fields(fields1, is_local) - fields[8] * 60000;
+ rv = JS_NewFloat64(ctx, d);
}
}
- for(i = 0; i < 7; i++)
- fields1[i] = fields[i];
- d = set_date_fields(fields1, is_local) - tz * 60000;
- rv = JS_NewFloat64(ctx, d);
-
-done:
JS_FreeValue(ctx, s);
return rv;
}
@@ -48736,9 +50555,7 @@ static JSValue js_date_Symbol_toPrimitive(JSContext *ctx, JSValueConst this_val,
}
switch (hint) {
case JS_ATOM_number:
-#ifdef CONFIG_BIGNUM
case JS_ATOM_integer:
-#endif
hint_num = HINT_NUMBER;
break;
case JS_ATOM_string:
@@ -48762,6 +50579,7 @@ static JSValue js_date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val,
if (isnan(v))
return JS_NAN;
else
+ /* assuming -8.64e15 <= v <= -8.64e15 */
return JS_NewInt64(ctx, getTimezoneOffset((int64_t)trunc(v)));
}
@@ -48900,6 +50718,23 @@ static const JSCFunctionListEntry js_date_proto_funcs[] = {
JS_CFUNC_DEF("toJSON", 1, js_date_toJSON ),
};
+JSValue JS_NewDate(JSContext *ctx, double epoch_ms)
+{
+ JSValue obj = js_create_from_ctor(ctx, JS_UNDEFINED, JS_CLASS_DATE);
+ if (JS_IsException(obj))
+ return JS_EXCEPTION;
+ JS_SetObjectData(ctx, obj, __JS_NewFloat64(ctx, time_clip(epoch_ms)));
+ return obj;
+}
+
+JS_BOOL JS_IsDate(JSValue v)
+{
+ JSObject *p;
+ if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT)
+ return FALSE;
+ return JS_VALUE_GET_OBJ(v)->class_id == JS_CLASS_DATE;
+}
+
void JS_AddIntrinsicDate(JSContext *ctx)
{
JSValueConst obj;
@@ -48917,7 +50752,7 @@ void JS_AddIntrinsicDate(JSContext *ctx)
void JS_AddIntrinsicEval(JSContext *ctx)
{
- ctx->eval_internal = JS_EvalInternalImpl;
+ ctx->eval_internal = __JS_EvalInternal;
}
#ifdef CONFIG_BIGNUM
@@ -49219,6 +51054,7 @@ void JS_AddIntrinsicOperators(JSContext *ctx)
js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT]);
js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
}
+#endif /* CONFIG_BIGNUM */
/* BigInt */
@@ -49236,14 +51072,20 @@ static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
case JS_TAG_BIG_INT:
break;
case JS_TAG_FLOAT64:
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
+#endif
{
bf_t *a, a_s;
a = JS_ToBigFloat(ctx, &a_s, val);
+ if (!a) {
+ JS_FreeValue(ctx, val);
+ return JS_EXCEPTION;
+ }
if (!bf_is_finite(a)) {
JS_FreeValue(ctx, val);
- val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to bigint");
+ val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to BigInt");
} else {
JSValue val1 = JS_NewBigInt(ctx);
bf_t *r;
@@ -49261,7 +51103,7 @@ static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
val = JS_ThrowOutOfMemory(ctx);
} else if (ret & BF_ST_INEXACT) {
JS_FreeValue(ctx, val1);
- val = JS_ThrowRangeError(ctx, "cannot convert to bigint: not an integer");
+ val = JS_ThrowRangeError(ctx, "cannot convert to BigInt: not an integer");
} else {
val = JS_CompactBigInt(ctx, val1);
}
@@ -49270,11 +51112,13 @@ static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
bf_delete(a);
}
break;
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_DECIMAL:
val = JS_ToStringFree(ctx, val);
- if (JS_IsException(val))
+ if (JS_IsException(val))
break;
goto redo;
+#endif
case JS_TAG_STRING:
val = JS_StringToBigIntErr(ctx, val);
break;
@@ -49287,7 +51131,7 @@ static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
case JS_TAG_UNDEFINED:
default:
JS_FreeValue(ctx, val);
- return JS_ThrowTypeError(ctx, "cannot convert to bigint");
+ return JS_ThrowTypeError(ctx, "cannot convert to BigInt");
}
return val;
}
@@ -49313,7 +51157,7 @@ static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val)
return JS_DupValue(ctx, p->u.object_data);
}
}
- return JS_ThrowTypeError(ctx, "not a bigint");
+ return JS_ThrowTypeError(ctx, "not a BigInt");
}
static JSValue js_bigint_toString(JSContext *ctx, JSValueConst this_val,
@@ -49347,6 +51191,7 @@ static JSValue js_bigint_valueOf(JSContext *ctx, JSValueConst this_val,
return js_thisBigIntValue(ctx, this_val);
}
+#ifdef CONFIG_BIGNUM
static JSValue js_bigint_div(JSContext *ctx,
JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
@@ -49475,6 +51320,7 @@ static JSValue js_bigint_op1(JSContext *ctx,
JS_FreeBigInt(ctx, a, &a_s);
return JS_NewBigInt64(ctx, res);
}
+#endif
static JSValue js_bigint_asUintN(JSContext *ctx,
JSValueConst this_val,
@@ -49519,6 +51365,7 @@ static JSValue js_bigint_asUintN(JSContext *ctx,
static const JSCFunctionListEntry js_bigint_funcs[] = {
JS_CFUNC_MAGIC_DEF("asUintN", 2, js_bigint_asUintN, 0 ),
JS_CFUNC_MAGIC_DEF("asIntN", 2, js_bigint_asUintN, 1 ),
+#ifdef CONFIG_BIGNUM
/* QuickJS extensions */
JS_CFUNC_MAGIC_DEF("tdiv", 2, js_bigint_div, BF_RNDZ ),
JS_CFUNC_MAGIC_DEF("fdiv", 2, js_bigint_div, BF_RNDD ),
@@ -49532,6 +51379,7 @@ static const JSCFunctionListEntry js_bigint_funcs[] = {
JS_CFUNC_MAGIC_DEF("sqrtrem", 1, js_bigint_sqrt, 1 ),
JS_CFUNC_MAGIC_DEF("floorLog2", 1, js_bigint_op1, 0 ),
JS_CFUNC_MAGIC_DEF("ctz", 1, js_bigint_op1, 1 ),
+#endif
};
static const JSCFunctionListEntry js_bigint_proto_funcs[] = {
@@ -49561,6 +51409,8 @@ void JS_AddIntrinsicBigInt(JSContext *ctx)
countof(js_bigint_funcs));
}
+#ifdef CONFIG_BIGNUM
+
/* BigFloat */
static JSValue js_thisBigFloatValue(JSContext *ctx, JSValueConst this_val)
@@ -50034,6 +51884,10 @@ static JSValue js_bigfloat_fop(JSContext *ctx, JSValueConst this_val,
if (JS_IsException(op1))
return op1;
a = JS_ToBigFloat(ctx, &a_s, op1);
+ if (!a) {
+ JS_FreeValue(ctx, op1);
+ return JS_EXCEPTION;
+ }
fe = &ctx->fp_env;
if (argc > 1) {
fe = JS_GetOpaque2(ctx, argv[1], JS_CLASS_FLOAT_ENV);
@@ -50132,7 +51986,11 @@ static JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val,
return op2;
}
a = JS_ToBigFloat(ctx, &a_s, op1);
+ if (!a)
+ goto fail1;
b = JS_ToBigFloat(ctx, &b_s, op2);
+ if (!b)
+ goto fail2;
fe = &ctx->fp_env;
if (argc > 2) {
fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV);
@@ -50142,10 +52000,12 @@ static JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val,
res = JS_NewBigFloat(ctx);
if (JS_IsException(res)) {
fail:
- if (a == &a_s)
- bf_delete(a);
if (b == &b_s)
bf_delete(b);
+ fail2:
+ if (a == &a_s)
+ bf_delete(a);
+ fail1:
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
return JS_EXCEPTION;
@@ -50338,9 +52198,9 @@ static JSValue js_float_env_proto_get_status(JSContext *ctx, JSValueConst this_v
case FE_RNDMODE:
return JS_NewInt32(ctx, fe->flags & BF_RND_MASK);
case FE_SUBNORMAL:
- return JS_NewBool(ctx, (fe->flags & BF_FLAG_SUBNORMAL) != 0);
+ return JS_NewBool(ctx, fe->flags & BF_FLAG_SUBNORMAL);
default:
- return JS_NewBool(ctx, (fe->status & magic) != 0);
+ return JS_NewBool(ctx, fe->status & magic);
}
}
@@ -51037,7 +52897,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
JS_PROP_HAS_GET | JS_PROP_HAS_SET |
JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE);
JS_FreeValue(ctx, obj1);
- JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, &ctx->throw_type_error, 1));
+ JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, (JSValueConst *)&ctx->throw_type_error, 1));
ctx->global_obj = JS_NewObject(ctx);
ctx->global_var_obj = JS_NewObjectProto(ctx, JS_NULL);
@@ -51063,11 +52923,13 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
JS_NewGlobalCConstructor2(ctx, obj1,
"Error", ctx->class_proto[JS_CLASS_ERROR]);
+ /* Used to squelch a -Wcast-function-type warning. */
+ JSCFunctionType ft = { .generic_magic = js_error_constructor };
for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
JSValue func_obj;
int n_args;
n_args = 1 + (i == JS_AGGREGATE_ERROR);
- func_obj = JS_NewCFunction3(ctx, (JSCFunction *)js_error_constructor,
+ func_obj = JS_NewCFunction3(ctx, ft.generic,
native_error_name[i], n_args,
JS_CFUNC_constructor_or_func_magic, i, obj1);
JS_NewGlobalCConstructor2(ctx, func_obj, native_error_name[i],
@@ -51094,8 +52956,22 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
/* XXX: create auto_initializer */
{
/* initialize Array.prototype[Symbol.unscopables] */
- char const unscopables[] = "copyWithin" "\0" "entries" "\0" "fill" "\0" "find" "\0"
- "findIndex" "\0" "flat" "\0" "flatMap" "\0" "includes" "\0" "keys" "\0" "values" "\0";
+ static const char unscopables[] =
+ "copyWithin" "\0"
+ "entries" "\0"
+ "fill" "\0"
+ "find" "\0"
+ "findIndex" "\0"
+ "findLast" "\0"
+ "findLastIndex" "\0"
+ "flat" "\0"
+ "flatMap" "\0"
+ "includes" "\0"
+ "keys" "\0"
+ "toReversed" "\0"
+ "toSorted" "\0"
+ "toSpliced" "\0"
+ "values" "\0";
const char *p = unscopables;
obj1 = JS_NewObjectProto(ctx, JS_NULL);
for(p = unscopables; *p; p += strlen(p) + 1) {
@@ -51219,9 +53095,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT] = {
0, 0, 0, 1, 1, 2, 2,
-#ifdef CONFIG_BIGNUM
3, 3, /* BigInt64Array, BigUint64Array */
-#endif
2, 3
};
@@ -51351,11 +53225,26 @@ static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val)
{
JSObject *p = JS_VALUE_GET_OBJ(val);
JSArrayBuffer *abuf = p->u.array_buffer;
+ struct list_head *el, *el1;
+
if (abuf) {
/* The ArrayBuffer finalizer may be called before the typed
array finalizers using it, so abuf->array_list is not
necessarily empty. */
- // assert(list_empty(&abuf->array_list));
+ list_for_each_safe(el, el1, &abuf->array_list) {
+ JSTypedArray *ta;
+ JSObject *p1;
+
+ ta = list_entry(el, JSTypedArray, link);
+ ta->link.prev = NULL;
+ ta->link.next = NULL;
+ p1 = ta->obj;
+ /* Note: the typed array length and offset fields are not modified */
+ if (p1->class_id != JS_CLASS_DATAVIEW) {
+ p1->u.array.count = 0;
+ p1->u.array.u.ptr = NULL;
+ }
+ }
if (abuf->shared && rt->sab_funcs.sab_free) {
rt->sab_funcs.sab_free(rt->sab_funcs.sab_opaque, abuf->data);
} else {
@@ -51665,6 +53554,16 @@ static JSValue js_typed_array_get_byteOffset(JSContext *ctx,
return JS_NewInt32(ctx, ta->offset);
}
+JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv,
+ JSTypedArrayEnum type)
+{
+ if (type < JS_TYPED_ARRAY_UINT8C || type > JS_TYPED_ARRAY_FLOAT64)
+ return JS_ThrowRangeError(ctx, "invalid typed array type");
+
+ return js_typed_array_constructor(ctx, JS_UNDEFINED, argc, argv,
+ JS_CLASS_UINT8C_ARRAY + type);
+}
+
/* Return the buffer associated to the typed array or an exception if
it is not a typed array or if the buffer is detached. pbyte_offset,
pbyte_length or pbytes_per_element can be NULL. */
@@ -51782,6 +53681,69 @@ fail:
return JS_EXCEPTION;
}
+static JSValue js_typed_array_at(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSObject *p;
+ int64_t idx, len;
+
+ p = get_typed_array(ctx, this_val, 0);
+ if (!p)
+ return JS_EXCEPTION;
+
+ if (typed_array_is_detached(ctx, p)) {
+ JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+ return JS_EXCEPTION;
+ }
+
+ if (JS_ToInt64Sat(ctx, &idx, argv[0]))
+ return JS_EXCEPTION;
+
+ len = p->u.array.count;
+ if (idx < 0)
+ idx = len + idx;
+ if (idx < 0 || idx >= len)
+ return JS_UNDEFINED;
+ return JS_GetPropertyInt64(ctx, this_val, idx);
+}
+
+static JSValue js_typed_array_with(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue arr, val;
+ JSObject *p;
+ int64_t idx, len;
+
+ p = get_typed_array(ctx, this_val, /*is_dataview*/0);
+ if (!p)
+ return JS_EXCEPTION;
+
+ if (JS_ToInt64Sat(ctx, &idx, argv[0]))
+ return JS_EXCEPTION;
+
+ len = p->u.array.count;
+ if (idx < 0)
+ idx = len + idx;
+ if (idx < 0 || idx >= len)
+ return JS_ThrowRangeError(ctx, "invalid array index");
+
+ val = JS_ToPrimitive(ctx, argv[1], HINT_NUMBER);
+ if (JS_IsException(val))
+ return JS_EXCEPTION;
+
+ arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,
+ p->class_id);
+ if (JS_IsException(arr)) {
+ JS_FreeValue(ctx, val);
+ return JS_EXCEPTION;
+ }
+ if (JS_SetPropertyInt64(ctx, arr, idx, val) < 0) {
+ JS_FreeValue(ctx, arr);
+ return JS_EXCEPTION;
+ }
+ return arr;
+}
+
static JSValue js_typed_array_set(JSContext *ctx,
JSValueConst this_val,
int argc, JSValueConst *argv)
@@ -52071,14 +54033,10 @@ static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val,
if (JS_ToUint32(ctx, &v, argv[0]))
return JS_EXCEPTION;
v64 = v;
- } else
-#ifdef CONFIG_BIGNUM
- if (p->class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
+ } else if (p->class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
if (JS_ToBigInt64(ctx, (int64_t *)&v64, argv[0]))
return JS_EXCEPTION;
- } else
-#endif
- {
+ } else {
double d;
if (JS_ToFloat64(ctx, &d, argv[0]))
return JS_EXCEPTION;
@@ -52140,12 +54098,13 @@ static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val,
}
static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int findIndex)
+ int argc, JSValueConst *argv, int mode)
{
JSValueConst func, this_arg;
JSValueConst args[3];
JSValue val, index_val, res;
- int len, k;
+ int len, k, end;
+ int dir;
val = JS_UNDEFINED;
len = js_typed_array_get_length_internal(ctx, this_val);
@@ -52160,7 +54119,16 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val,
if (argc > 1)
this_arg = argv[1];
- for(k = 0; k < len; k++) {
+ k = 0;
+ dir = 1;
+ end = len;
+ if (mode == ArrayFindLast || mode == ArrayFindLastIndex) {
+ k = len - 1;
+ dir = -1;
+ end = -1;
+ }
+
+ for(; k != end; k += dir) {
index_val = JS_NewInt32(ctx, k);
val = JS_GetPropertyValue(ctx, this_val, index_val);
if (JS_IsException(val))
@@ -52172,7 +54140,7 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val,
if (JS_IsException(res))
goto exception;
if (JS_ToBoolFree(ctx, res)) {
- if (findIndex) {
+ if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) {
JS_FreeValue(ctx, val);
return index_val;
} else {
@@ -52181,7 +54149,7 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val,
}
JS_FreeValue(ctx, val);
}
- if (findIndex)
+ if (mode == ArrayFindIndex || mode == ArrayFindLastIndex)
return JS_NewInt32(ctx, -1);
else
return JS_UNDEFINED;
@@ -52193,7 +54161,7 @@ exception:
#define special_indexOf 0
#define special_lastIndexOf 1
-#define special_includes (-1)
+#define special_includes -1
static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int special)
@@ -52260,13 +54228,14 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
is_int = 1;
v64 = JS_VALUE_GET_INT(argv[0]);
d = v64;
- } else if (tag == JS_TAG_FLOAT64) {
- d = JS_VALUE_GET_FLOAT64(argv[0]);
- v64 = d;
- is_int = (v64 == d);
} else
-#ifdef CONFIG_BIGNUM
- if (tag == JS_TAG_BIG_INT) {
+ if (tag == JS_TAG_FLOAT64) {
+ d = JS_VALUE_GET_FLOAT64(argv[0]);
+ if (d >= INT64_MIN && d < 0x1p63) {
+ v64 = d;
+ is_int = (v64 == d);
+ }
+ } else if (tag == JS_TAG_BIG_INT) {
JSBigFloat *p1 = JS_VALUE_GET_PTR(argv[0]);
if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) {
@@ -52280,9 +54249,7 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
}
d = 0;
is_bigint = 1;
- } else
-#endif
- {
+ } else {
goto done;
}
@@ -52399,7 +54366,6 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
}
}
break;
-#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT64_ARRAY:
if (is_bigint || (is_math_mode(ctx) && is_int &&
v64 >= -MAX_SAFE_INTEGER &&
@@ -52423,7 +54389,6 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
}
}
break;
-#endif
}
done:
@@ -52558,6 +54523,24 @@ static JSValue js_typed_array_reverse(JSContext *ctx, JSValueConst this_val,
return JS_DupValue(ctx, this_val);
}
+static JSValue js_typed_array_toReversed(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue arr, ret;
+ JSObject *p;
+
+ p = get_typed_array(ctx, this_val, /*is_dataview*/0);
+ if (!p)
+ return JS_EXCEPTION;
+ arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,
+ p->class_id);
+ if (JS_IsException(arr))
+ return JS_EXCEPTION;
+ ret = js_typed_array_reverse(ctx, arr, argc, argv);
+ JS_FreeValue(ctx, arr);
+ return ret;
+}
+
static JSValue js_typed_array_slice(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
@@ -52704,7 +54687,6 @@ static int js_TA_cmp_uint32(const void *a, const void *b, void *opaque) {
return (y < x) - (y > x);
}
-#ifdef CONFIG_BIGNUM
static int js_TA_cmp_int64(const void *a, const void *b, void *opaque) {
int64_t x = *(const int64_t *)a;
int64_t y = *(const int64_t *)b;
@@ -52716,7 +54698,6 @@ static int js_TA_cmp_uint64(const void *a, const void *b, void *opaque) {
uint64_t y = *(const uint64_t *)b;
return (y < x) - (y > x);
}
-#endif
static int js_TA_cmp_float32(const void *a, const void *b, void *opaque) {
return js_cmp_doubles(*(const float *)a, *(const float *)b);
@@ -52750,7 +54731,6 @@ static JSValue js_TA_get_uint32(JSContext *ctx, const void *a) {
return JS_NewUint32(ctx, *(const uint32_t *)a);
}
-#ifdef CONFIG_BIGNUM
static JSValue js_TA_get_int64(JSContext *ctx, const void *a) {
return JS_NewBigInt64(ctx, *(int64_t *)a);
}
@@ -52758,19 +54738,18 @@ static JSValue js_TA_get_int64(JSContext *ctx, const void *a) {
static JSValue js_TA_get_uint64(JSContext *ctx, const void *a) {
return JS_NewBigUint64(ctx, *(uint64_t *)a);
}
-#endif
static JSValue js_TA_get_float32(JSContext *ctx, const void *a) {
- return JS_NewFloat64Impl(ctx, *(const float *)a);
+ return __JS_NewFloat64(ctx, *(const float *)a);
}
static JSValue js_TA_get_float64(JSContext *ctx, const void *a) {
- return JS_NewFloat64Impl(ctx, *(const double *)a);
+ return __JS_NewFloat64(ctx, *(const double *)a);
}
struct TA_sort_context {
JSContext *ctx;
- int exception;
+ int exception; /* 1 = exception, 2 = detached typed array */
JSValueConst arr;
JSValueConst cmp;
JSValue (*getfun)(JSContext *ctx, const void *a);
@@ -52788,6 +54767,8 @@ static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) {
cmp = 0;
if (!psc->exception) {
+ /* Note: the typed array can be detached without causing an
+ error */
a_idx = *(uint32_t *)a;
b_idx = *(uint32_t *)b;
argv[0] = psc->getfun(ctx, psc->array_ptr +
@@ -52815,8 +54796,9 @@ static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) {
/* make sort stable: compare array offsets */
cmp = (a_idx > b_idx) - (a_idx < b_idx);
}
- if (validate_typed_array(ctx, psc->arr) < 0) {
- psc->exception = 1;
+ if (unlikely(typed_array_is_detached(ctx,
+ JS_VALUE_GET_PTR(psc->arr)))) {
+ psc->exception = 2;
}
done:
JS_FreeValue(ctx, argv[0]);
@@ -52840,11 +54822,11 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val,
tsc.arr = this_val;
tsc.cmp = argv[0];
+ if (!JS_IsUndefined(tsc.cmp) && check_function(ctx, tsc.cmp))
+ return JS_EXCEPTION;
len = js_typed_array_get_length_internal(ctx, this_val);
if (len < 0)
return JS_EXCEPTION;
- if (!JS_IsUndefined(tsc.cmp) && check_function(ctx, tsc.cmp))
- return JS_EXCEPTION;
if (len > 1) {
p = JS_VALUE_GET_OBJ(this_val);
@@ -52874,7 +54856,6 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val,
tsc.getfun = js_TA_get_uint32;
cmpfun = js_TA_cmp_uint32;
break;
-#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT64_ARRAY:
tsc.getfun = js_TA_get_int64;
cmpfun = js_TA_cmp_int64;
@@ -52883,7 +54864,6 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val,
tsc.getfun = js_TA_get_uint64;
cmpfun = js_TA_cmp_uint64;
break;
-#endif
case JS_CLASS_FLOAT32_ARRAY:
tsc.getfun = js_TA_get_float32;
cmpfun = js_TA_cmp_float32;
@@ -52912,44 +54892,48 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val,
tsc.elt_size = elt_size;
rqsort(array_idx, len, sizeof(array_idx[0]),
js_TA_cmp_generic, &tsc);
- if (tsc.exception)
- goto fail;
- array_tmp = js_malloc(ctx, len * elt_size);
- if (!array_tmp) {
- fail:
- js_free(ctx, array_idx);
- return JS_EXCEPTION;
- }
- memcpy(array_tmp, array_ptr, len * elt_size);
- switch(elt_size) {
- case 1:
- for(i = 0; i < len; i++) {
- j = array_idx[i];
- ((uint8_t *)array_ptr)[i] = ((uint8_t *)array_tmp)[j];
- }
- break;
- case 2:
- for(i = 0; i < len; i++) {
- j = array_idx[i];
- ((uint16_t *)array_ptr)[i] = ((uint16_t *)array_tmp)[j];
- }
- break;
- case 4:
- for(i = 0; i < len; i++) {
- j = array_idx[i];
- ((uint32_t *)array_ptr)[i] = ((uint32_t *)array_tmp)[j];
+ if (tsc.exception) {
+ if (tsc.exception == 1)
+ goto fail;
+ /* detached typed array during the sort: no error */
+ } else {
+ array_tmp = js_malloc(ctx, len * elt_size);
+ if (!array_tmp) {
+ fail:
+ js_free(ctx, array_idx);
+ return JS_EXCEPTION;
}
- break;
- case 8:
- for(i = 0; i < len; i++) {
- j = array_idx[i];
- ((uint64_t *)array_ptr)[i] = ((uint64_t *)array_tmp)[j];
+ memcpy(array_tmp, array_ptr, len * elt_size);
+ switch(elt_size) {
+ case 1:
+ for(i = 0; i < len; i++) {
+ j = array_idx[i];
+ ((uint8_t *)array_ptr)[i] = ((uint8_t *)array_tmp)[j];
+ }
+ break;
+ case 2:
+ for(i = 0; i < len; i++) {
+ j = array_idx[i];
+ ((uint16_t *)array_ptr)[i] = ((uint16_t *)array_tmp)[j];
+ }
+ break;
+ case 4:
+ for(i = 0; i < len; i++) {
+ j = array_idx[i];
+ ((uint32_t *)array_ptr)[i] = ((uint32_t *)array_tmp)[j];
+ }
+ break;
+ case 8:
+ for(i = 0; i < len; i++) {
+ j = array_idx[i];
+ ((uint64_t *)array_ptr)[i] = ((uint64_t *)array_tmp)[j];
+ }
+ break;
+ default:
+ abort();
}
- break;
- default:
- abort();
+ js_free(ctx, array_tmp);
}
- js_free(ctx, array_tmp);
js_free(ctx, array_idx);
} else {
rqsort(array_ptr, len, elt_size, cmpfun, &tsc);
@@ -52960,6 +54944,24 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val,
return JS_DupValue(ctx, this_val);
}
+static JSValue js_typed_array_toSorted(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue arr, ret;
+ JSObject *p;
+
+ p = get_typed_array(ctx, this_val, /*is_dataview*/0);
+ if (!p)
+ return JS_EXCEPTION;
+ arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,
+ p->class_id);
+ if (JS_IsException(arr))
+ return JS_EXCEPTION;
+ ret = js_typed_array_sort(ctx, arr, argc, argv);
+ JS_FreeValue(ctx, arr);
+ return ret;
+}
+
static const JSCFunctionListEntry js_typed_array_base_funcs[] = {
JS_CFUNC_DEF("from", 1, js_typed_array_from ),
JS_CFUNC_DEF("of", 0, js_typed_array_of ),
@@ -52971,6 +54973,8 @@ static const JSCFunctionListEntry js_typed_array_base_funcs[] = {
static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = {
JS_CGETSET_DEF("length", js_typed_array_get_length, NULL ),
+ JS_CFUNC_DEF("at", 1, js_typed_array_at ),
+ JS_CFUNC_DEF("with", 2, js_typed_array_with ),
JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_buffer, NULL, 0 ),
JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_byteLength, NULL, 0 ),
JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_byteOffset, NULL, 0 ),
@@ -52989,12 +54993,16 @@ static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = {
JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce | special_TA ),
JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight | special_TA ),
JS_CFUNC_DEF("fill", 1, js_typed_array_fill ),
- JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, 0 ),
- JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, 1 ),
+ JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, ArrayFind ),
+ JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, ArrayFindIndex ),
+ JS_CFUNC_MAGIC_DEF("findLast", 1, js_typed_array_find, ArrayFindLast ),
+ JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_typed_array_find, ArrayFindLastIndex ),
JS_CFUNC_DEF("reverse", 0, js_typed_array_reverse ),
+ JS_CFUNC_DEF("toReversed", 0, js_typed_array_toReversed ),
JS_CFUNC_DEF("slice", 2, js_typed_array_slice ),
JS_CFUNC_DEF("subarray", 2, js_typed_array_subarray ),
JS_CFUNC_DEF("sort", 1, js_typed_array_sort ),
+ JS_CFUNC_DEF("toSorted", 1, js_typed_array_toSorted ),
JS_CFUNC_MAGIC_DEF("join", 1, js_typed_array_join, 0 ),
JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_typed_array_join, 1 ),
JS_CFUNC_MAGIC_DEF("indexOf", 1, js_typed_array_indexOf, special_indexOf ),
@@ -53141,7 +55149,7 @@ static JSValue js_typed_array_constructor_ta(JSContext *ctx,
{
JSObject *p, *src_buffer;
JSTypedArray *ta;
- JSValue ctor, obj, buffer;
+ JSValue obj, buffer;
uint32_t len, i;
int size_log2;
JSArrayBuffer *src_abuf, *abuf;
@@ -53158,19 +55166,9 @@ static JSValue js_typed_array_constructor_ta(JSContext *ctx,
len = p->u.array.count;
src_buffer = ta->buffer;
src_abuf = src_buffer->u.array_buffer;
- if (!src_abuf->shared) {
- ctor = JS_SpeciesConstructor(ctx, JS_MKPTR(JS_TAG_OBJECT, src_buffer),
- JS_UNDEFINED);
- if (JS_IsException(ctor))
- goto fail;
- } else {
- /* force ArrayBuffer default constructor */
- ctor = JS_UNDEFINED;
- }
size_log2 = typed_array_size_log2(classid);
- buffer = js_array_buffer_constructor1(ctx, ctor,
+ buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
(uint64_t)len << size_log2);
- JS_FreeValue(ctx, ctor);
if (JS_IsException(buffer))
goto fail;
/* necessary because it could have been detached */
@@ -53276,7 +55274,7 @@ static void js_typed_array_finalizer(JSRuntime *rt, JSValue val)
if (ta) {
/* during the GC the finalizers are called in an arbitrary
order so the ArrayBuffer finalizer may have been called */
- if (JS_IsLiveObject(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer))) {
+ if (ta->link.next) {
list_del(&ta->link);
}
JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
@@ -53359,7 +55357,8 @@ static JSValue js_dataview_getValue(JSContext *ctx,
{
JSTypedArray *ta;
JSArrayBuffer *abuf;
- int is_swap, size;
+ BOOL littleEndian, is_swap;
+ int size;
uint8_t *ptr;
uint32_t v;
uint64_t pos;
@@ -53370,12 +55369,8 @@ static JSValue js_dataview_getValue(JSContext *ctx,
size = 1 << typed_array_size_log2(class_id);
if (JS_ToIndex(ctx, &pos, argv[0]))
return JS_EXCEPTION;
- is_swap = FALSE;
- if (argc > 1)
- is_swap = JS_ToBool(ctx, argv[1]);
-#ifndef WORDS_BIGENDIAN
- is_swap ^= 1;
-#endif
+ littleEndian = argc > 1 && JS_ToBool(ctx, argv[1]);
+ is_swap = littleEndian ^ !is_be();
abuf = ta->buffer->u.array_buffer;
if (abuf->detached)
return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
@@ -53387,7 +55382,7 @@ static JSValue js_dataview_getValue(JSContext *ctx,
case JS_CLASS_INT8_ARRAY:
return JS_NewInt32(ctx, *(int8_t *)ptr);
case JS_CLASS_UINT8_ARRAY:
- return JS_NewInt32(ctx, *ptr);
+ return JS_NewInt32(ctx, *(uint8_t *)ptr);
case JS_CLASS_INT16_ARRAY:
v = get_u16(ptr);
if (is_swap)
@@ -53408,7 +55403,6 @@ static JSValue js_dataview_getValue(JSContext *ctx,
if (is_swap)
v = bswap32(v);
return JS_NewUint32(ctx, v);
-#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT64_ARRAY:
{
uint64_t v;
@@ -53427,7 +55421,6 @@ static JSValue js_dataview_getValue(JSContext *ctx,
return JS_NewBigUint64(ctx, v);
}
break;
-#endif
case JS_CLASS_FLOAT32_ARRAY:
{
union {
@@ -53438,7 +55431,7 @@ static JSValue js_dataview_getValue(JSContext *ctx,
if (is_swap)
v = bswap32(v);
u.i = v;
- return JS_NewFloat64Impl(ctx, u.f);
+ return __JS_NewFloat64(ctx, u.f);
}
case JS_CLASS_FLOAT64_ARRAY:
{
@@ -53449,7 +55442,7 @@ static JSValue js_dataview_getValue(JSContext *ctx,
u.i = get_u64(ptr);
if (is_swap)
u.i = bswap64(u.i);
- return JS_NewFloat64Impl(ctx, u.f);
+ return __JS_NewFloat64(ctx, u.f);
}
default:
abort();
@@ -53462,7 +55455,8 @@ static JSValue js_dataview_setValue(JSContext *ctx,
{
JSTypedArray *ta;
JSArrayBuffer *abuf;
- int is_swap, size;
+ BOOL littleEndian, is_swap;
+ int size;
uint8_t *ptr;
uint64_t v64;
uint32_t v;
@@ -53481,14 +55475,10 @@ static JSValue js_dataview_setValue(JSContext *ctx,
if (class_id <= JS_CLASS_UINT32_ARRAY) {
if (JS_ToUint32(ctx, &v, val))
return JS_EXCEPTION;
- } else
-#ifdef CONFIG_BIGNUM
- if (class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
+ } else if (class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
if (JS_ToBigInt64(ctx, (int64_t *)&v64, val))
return JS_EXCEPTION;
- } else
-#endif
- {
+ } else {
double d;
if (JS_ToFloat64(ctx, &d, val))
return JS_EXCEPTION;
@@ -53505,12 +55495,8 @@ static JSValue js_dataview_setValue(JSContext *ctx,
v64 = u.u64;
}
}
- is_swap = FALSE;
- if (argc > 2)
- is_swap = JS_ToBool(ctx, argv[2]);
-#ifndef WORDS_BIGENDIAN
- is_swap ^= 1;
-#endif
+ littleEndian = argc > 2 && JS_ToBool(ctx, argv[2]);
+ is_swap = littleEndian ^ !is_be();
abuf = ta->buffer->u.array_buffer;
if (abuf->detached)
return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
@@ -53536,10 +55522,8 @@ static JSValue js_dataview_setValue(JSContext *ctx,
v = bswap32(v);
put_u32(ptr, v);
break;
-#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT64_ARRAY:
case JS_CLASS_BIG_UINT64_ARRAY:
-#endif
case JS_CLASS_FLOAT64_ARRAY:
if (is_swap)
v64 = bswap64(v64);
@@ -53561,10 +55545,8 @@ static const JSCFunctionListEntry js_dataview_proto_funcs[] = {
JS_CFUNC_MAGIC_DEF("getUint16", 1, js_dataview_getValue, JS_CLASS_UINT16_ARRAY ),
JS_CFUNC_MAGIC_DEF("getInt32", 1, js_dataview_getValue, JS_CLASS_INT32_ARRAY ),
JS_CFUNC_MAGIC_DEF("getUint32", 1, js_dataview_getValue, JS_CLASS_UINT32_ARRAY ),
-#ifdef CONFIG_BIGNUM
JS_CFUNC_MAGIC_DEF("getBigInt64", 1, js_dataview_getValue, JS_CLASS_BIG_INT64_ARRAY ),
JS_CFUNC_MAGIC_DEF("getBigUint64", 1, js_dataview_getValue, JS_CLASS_BIG_UINT64_ARRAY ),
-#endif
JS_CFUNC_MAGIC_DEF("getFloat32", 1, js_dataview_getValue, JS_CLASS_FLOAT32_ARRAY ),
JS_CFUNC_MAGIC_DEF("getFloat64", 1, js_dataview_getValue, JS_CLASS_FLOAT64_ARRAY ),
JS_CFUNC_MAGIC_DEF("setInt8", 2, js_dataview_setValue, JS_CLASS_INT8_ARRAY ),
@@ -53573,10 +55555,8 @@ static const JSCFunctionListEntry js_dataview_proto_funcs[] = {
JS_CFUNC_MAGIC_DEF("setUint16", 2, js_dataview_setValue, JS_CLASS_UINT16_ARRAY ),
JS_CFUNC_MAGIC_DEF("setInt32", 2, js_dataview_setValue, JS_CLASS_INT32_ARRAY ),
JS_CFUNC_MAGIC_DEF("setUint32", 2, js_dataview_setValue, JS_CLASS_UINT32_ARRAY ),
-#ifdef CONFIG_BIGNUM
JS_CFUNC_MAGIC_DEF("setBigInt64", 2, js_dataview_setValue, JS_CLASS_BIG_INT64_ARRAY ),
JS_CFUNC_MAGIC_DEF("setBigUint64", 2, js_dataview_setValue, JS_CLASS_BIG_UINT64_ARRAY ),
-#endif
JS_CFUNC_MAGIC_DEF("setFloat32", 2, js_dataview_setValue, JS_CLASS_FLOAT32_ARRAY ),
JS_CFUNC_MAGIC_DEF("setFloat64", 2, js_dataview_setValue, JS_CLASS_FLOAT64_ARRAY ),
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "DataView", JS_PROP_CONFIGURABLE ),
@@ -53613,20 +55593,12 @@ static void *js_atomics_get_ptr(JSContext *ctx,
if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
goto fail;
p = JS_VALUE_GET_OBJ(obj);
-#ifdef CONFIG_BIGNUM
if (is_waitable)
err = (p->class_id != JS_CLASS_INT32_ARRAY &&
p->class_id != JS_CLASS_BIG_INT64_ARRAY);
else
err = !(p->class_id >= JS_CLASS_INT8_ARRAY &&
p->class_id <= JS_CLASS_BIG_UINT64_ARRAY);
-#else
- if (is_waitable)
- err = (p->class_id != JS_CLASS_INT32_ARRAY);
- else
- err = !(p->class_id >= JS_CLASS_INT8_ARRAY &&
- p->class_id <= JS_CLASS_UINT32_ARRAY);
-#endif
if (err) {
fail:
JS_ThrowTypeError(ctx, "integer TypedArray expected");
@@ -53668,11 +55640,7 @@ static JSValue js_atomics_op(JSContext *ctx,
int argc, JSValueConst *argv, int op)
{
int size_log2;
-#ifdef CONFIG_BIGNUM
uint64_t v, a, rep_val;
-#else
- uint32_t v, a, rep_val;
-#endif
void *ptr;
JSValue ret;
JSClassID class_id;
@@ -53686,7 +55654,6 @@ static JSValue js_atomics_op(JSContext *ctx,
if (op == ATOMICS_OP_LOAD) {
v = 0;
} else {
-#ifdef CONFIG_BIGNUM
if (size_log2 == 3) {
int64_t v64;
if (JS_ToBigInt64(ctx, &v64, argv[2]))
@@ -53697,9 +55664,7 @@ static JSValue js_atomics_op(JSContext *ctx,
return JS_EXCEPTION;
rep_val = v64;
}
- } else
-#endif
- {
+ } else {
uint32_t v32;
if (JS_ToUint32(ctx, &v32, argv[2]))
return JS_EXCEPTION;
@@ -53716,7 +55681,6 @@ static JSValue js_atomics_op(JSContext *ctx,
switch(op | (size_log2 << 3)) {
-#ifdef CONFIG_BIGNUM
#define OP(op_name, func_name) \
case ATOMICS_OP_ ## op_name | (0 << 3): \
a = func_name((_Atomic(uint8_t) *)ptr, v); \
@@ -53730,18 +55694,7 @@ static JSValue js_atomics_op(JSContext *ctx,
case ATOMICS_OP_ ## op_name | (3 << 3): \
a = func_name((_Atomic(uint64_t) *)ptr, v); \
break;
-#else
-#define OP(op_name, func_name) \
- case ATOMICS_OP_ ## op_name | (0 << 3): \
- a = func_name((_Atomic(uint8_t) *)ptr, v); \
- break; \
- case ATOMICS_OP_ ## op_name | (1 << 3): \
- a = func_name((_Atomic(uint16_t) *)ptr, v); \
- break; \
- case ATOMICS_OP_ ## op_name | (2 << 3): \
- a = func_name((_Atomic(uint32_t) *)ptr, v); \
- break;
-#endif
+
OP(ADD, atomic_fetch_add)
OP(AND, atomic_fetch_and)
OP(OR, atomic_fetch_or)
@@ -53759,11 +55712,9 @@ static JSValue js_atomics_op(JSContext *ctx,
case ATOMICS_OP_LOAD | (2 << 3):
a = atomic_load((_Atomic(uint32_t) *)ptr);
break;
-#ifdef CONFIG_BIGNUM
case ATOMICS_OP_LOAD | (3 << 3):
a = atomic_load((_Atomic(uint64_t) *)ptr);
break;
-#endif
case ATOMICS_OP_COMPARE_EXCHANGE | (0 << 3):
{
@@ -53786,7 +55737,6 @@ static JSValue js_atomics_op(JSContext *ctx,
a = v1;
}
break;
-#ifdef CONFIG_BIGNUM
case ATOMICS_OP_COMPARE_EXCHANGE | (3 << 3):
{
uint64_t v1 = v;
@@ -53794,7 +55744,6 @@ static JSValue js_atomics_op(JSContext *ctx,
a = v1;
}
break;
-#endif
default:
abort();
}
@@ -53819,14 +55768,12 @@ static JSValue js_atomics_op(JSContext *ctx,
case JS_CLASS_UINT32_ARRAY:
ret = JS_NewUint32(ctx, a);
break;
-#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT64_ARRAY:
ret = JS_NewBigInt64(ctx, a);
break;
case JS_CLASS_BIG_UINT64_ARRAY:
ret = JS_NewBigUint64(ctx, a);
break;
-#endif
default:
abort();
}
@@ -53846,7 +55793,6 @@ static JSValue js_atomics_store(JSContext *ctx,
argv[0], argv[1], 0);
if (!ptr)
return JS_EXCEPTION;
-#ifdef CONFIG_BIGNUM
if (size_log2 == 3) {
int64_t v64;
ret = JS_ToBigIntValueFree(ctx, JS_DupValue(ctx, argv[2]));
@@ -53859,9 +55805,7 @@ static JSValue js_atomics_store(JSContext *ctx,
if (abuf->detached)
return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
atomic_store((_Atomic(uint64_t) *)ptr, v64);
- } else
-#endif
- {
+ } else {
uint32_t v;
/* XXX: spec, would be simpler to return the written value */
ret = JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[2]));
@@ -53897,11 +55841,7 @@ static JSValue js_atomics_isLockFree(JSContext *ctx,
int v, ret;
if (JS_ToInt32Sat(ctx, &v, argv[0]))
return JS_EXCEPTION;
- ret = (v == 1 || v == 2 || v == 4
-#ifdef CONFIG_BIGNUM
- || v == 8
-#endif
- );
+ ret = (v == 1 || v == 2 || v == 4 || v == 8);
return JS_NewBool(ctx, ret);
}
@@ -53933,20 +55873,18 @@ static JSValue js_atomics_wait(JSContext *ctx,
argv[0], argv[1], 2);
if (!ptr)
return JS_EXCEPTION;
-#ifdef CONFIG_BIGNUM
if (size_log2 == 3) {
if (JS_ToBigInt64(ctx, &v, argv[2]))
return JS_EXCEPTION;
- } else
-#endif
- {
+ } else {
if (JS_ToInt32(ctx, &v32, argv[2]))
return JS_EXCEPTION;
v = v32;
}
if (JS_ToFloat64(ctx, &d, argv[3]))
return JS_EXCEPTION;
- if (isnan(d) || d > INT64_MAX)
+ /* must use INT64_MAX + 1 because INT64_MAX cannot be exactly represented as a double */
+ if (isnan(d) || d >= 0x1p63)
timeout = INT64_MAX;
else if (d < 0)
timeout = 0;
@@ -54124,6 +56062,8 @@ void JS_AddIntrinsicTypedArrays(JSContext *ctx)
countof(js_typed_array_base_funcs));
JS_SetConstructor(ctx, typed_array_base_func, typed_array_base_proto);
+ /* Used to squelch a -Wcast-function-type warning. */
+ JSCFunctionType ft = { .generic_magic = js_typed_array_constructor };
for(i = JS_CLASS_UINT8C_ARRAY; i < JS_CLASS_UINT8C_ARRAY + JS_TYPED_ARRAY_COUNT; i++) {
JSValue func_obj;
char buf[ATOM_GET_STR_BUF_SIZE];
@@ -54136,7 +56076,7 @@ void JS_AddIntrinsicTypedArrays(JSContext *ctx)
0);
name = JS_AtomGetStr(ctx, buf, sizeof(buf),
JS_ATOM_Uint8ClampedArray + i - JS_CLASS_UINT8C_ARRAY);
- func_obj = JS_NewCFunction3(ctx, (JSCFunction *)js_typed_array_constructor,
+ func_obj = JS_NewCFunction3(ctx, ft.generic,
name, 3, JS_CFUNC_constructor_magic, i,
typed_array_base_func);
JS_NewGlobalCConstructor2(ctx, func_obj, name, ctx->class_proto[i]);
@@ -54220,6 +56160,17 @@ JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *func,
magic);
}
+#ifdef JS_NAN_BOXING
+JSValue mkVal(int32_t tag, int32_t val)
+{
+ return ((uint64_t)(tag) << 32) | (uint32_t)(val);
+}
+
+JSValue mkPtr(int32_t tag, void *p)
+{
+ return ((uint64_t)(tag) << 32) | (uintptr_t)(p);
+}
+#else
JSValue mkVal(int32_t tag, int32_t val)
{
return (JSValue){ (JSValueUnion){ .int32 = val }, tag };
@@ -54229,6 +56180,7 @@ JSValue mkPtr(int32_t tag, void *p)
{
return (JSValue){ (JSValueUnion){ .ptr = p }, tag };
}
+#endif
void JS_FreeValue(JSContext *ctx, JSValue v) {
if (JS_VALUE_HAS_REF_COUNT(v)) {
@@ -54237,7 +56189,7 @@ void JS_FreeValue(JSContext *ctx, JSValue v) {
notifyRefCountDecrease(p);
#endif
if (--p->ref_count <= 0) {
- JS_FreeValueImpl(ctx, v);
+ __JS_FreeValue(ctx, v);
}
}
}
@@ -54248,7 +56200,7 @@ void JS_FreeValueRT(JSRuntime *rt, JSValue v) {
notifyRefCountDecrease(p);
#endif
if (--p->ref_count <= 0) {
- JS_FreeValueRTImpl(rt, v);
+ __JS_FreeValueRT(rt, v);
}
}
}
@@ -54269,7 +56221,7 @@ JSValue JS_NewInt64(JSContext *ctx, int64_t val) {
if (val == (int32_t)val) {
v = JS_NewInt32(ctx, (int32_t)val);
} else {
- v = JS_NewFloat64Impl(ctx, (double)val);
+ v = __JS_NewFloat64(ctx, (double)val);
}
return v;
}
@@ -54278,29 +56230,29 @@ JSValue JS_NewUint32(JSContext *ctx, uint32_t val) {
if (val <= 0x7fffffff) {
v = JS_NewInt32(ctx, val);
} else {
- v = JS_NewFloat64Impl(ctx, val);
+ v = __JS_NewFloat64(ctx, val);
}
return v;
}
-JSValue JS_NewFloat64(JSContext *ctx, double d) {
- JSValue v;
+JSValue JS_NewFloat64(JSContext *ctx, double d)
+{
int32_t val;
union {
double d;
uint64_t u;
} u, t;
- u.d = d;
- val = (int32_t)d;
- t.d = val;
- /* -0 cannot be represented as integer, so we compare the bit
- representation */
- if (u.u == t.u) {
- v = JS_MKVAL(JS_TAG_INT, val);
- } else {
- v = JS_NewFloat64Impl(ctx, d);
+ if (d >= INT32_MIN && d <= INT32_MAX) {
+ u.d = d;
+ val = (int32_t)d;
+ t.d = val;
+ /* -0 cannot be represented as integer, so we compare the bit
+ representation */
+ if (u.u == t.u)
+ return JS_MKVAL(JS_TAG_INT, val);
}
- return v;
+ return __JS_NewFloat64(ctx, d);
}
+
JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, const char *name,
int length) {
return JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_generic, 0);
diff --git a/src/shared/quickjs/quickjs.diff b/src/shared/quickjs/quickjs.diff
deleted file mode 100644
index e87999050..000000000
--- a/src/shared/quickjs/quickjs.diff
+++ /dev/null
@@ -1,4061 +0,0 @@
-diff --git a/cutils.c b/cutils.c
-index a02fb76..1f66fff 100644
---- a/cutils.c
-+++ b/cutils.c
-@@ -166,8 +166,7 @@ int dbuf_putstr(DynBuf *s, const char *str)
- return dbuf_put(s, (const uint8_t *)str, strlen(str));
- }
-
--int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
-- const char *fmt, ...)
-+int FORMAT_ATTR(2, 3) dbuf_printf(DynBuf *s, const char *fmt, ...)
- {
- va_list ap;
- char buf[128];
-diff --git a/cutils.h b/cutils.h
-index 31f7cd8..ee0ce4a 100644
---- a/cutils.h
-+++ b/cutils.h
-@@ -28,14 +28,33 @@
- #include <stdlib.h>
- #include <inttypes.h>
-
-+#if defined(_MSC_VER)
-+#include <BaseTsd.h>
-+typedef SSIZE_T ssize_t;
-+#else
-+#include <sys/types.h>
-+#endif
-+
- /* set if CPU is big endian */
- #undef WORDS_BIGENDIAN
-
-+#ifdef __GNUC__
- #define likely(x) __builtin_expect(!!(x), 1)
- #define unlikely(x) __builtin_expect(!!(x), 0)
- #define force_inline inline __attribute__((always_inline))
- #define no_inline __attribute__((noinline))
--#define __maybe_unused __attribute__((unused))
-+#define maybe_unused __attribute__((unused))
-+#else
-+#define likely(x) (x)
-+#define unlikely(x) (x)
-+#define force_inline
-+#define no_inline
-+#define maybe_unused
-+#endif
-+
-+#ifdef _MSC_VER
-+#define alloca _alloca
-+#endif
-
- #define xglue(x, y) x ## y
- #define glue(x, y) xglue(x, y)
-@@ -114,38 +133,24 @@ static inline int64_t min_int64(int64_t a, int64_t b)
- /* WARNING: undefined if a = 0 */
- static inline int clz32(unsigned int a)
- {
-+#ifdef _MSC_VER
-+ return (int) __lzcnt(a);
-+#else
- return __builtin_clz(a);
-+#endif
- }
-
--/* WARNING: undefined if a = 0 */
--static inline int clz64(uint64_t a)
--{
-- return __builtin_clzll(a);
--}
--
--/* WARNING: undefined if a = 0 */
--static inline int ctz32(unsigned int a)
--{
-- return __builtin_ctz(a);
--}
--
--/* WARNING: undefined if a = 0 */
--static inline int ctz64(uint64_t a)
--{
-- return __builtin_ctzll(a);
--}
--
--struct __attribute__((packed)) packed_u64 {
-+#pragma pack(push, 1)
-+struct packed_u64 {
- uint64_t v;
- };
--
--struct __attribute__((packed)) packed_u32 {
-+struct packed_u32 {
- uint32_t v;
- };
--
--struct __attribute__((packed)) packed_u16 {
-+struct packed_u16 {
- uint16_t v;
- };
-+#pragma pack(pop)
-
- static inline uint64_t get_u64(const uint8_t *tab)
- {
-@@ -262,8 +267,15 @@ static inline int dbuf_put_u64(DynBuf *s, uint64_t val)
- {
- return dbuf_put(s, (uint8_t *)&val, 8);
- }
--int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
-- const char *fmt, ...);
-+
-+#ifdef __GNUC__
-+#define FORMAT_ATTR(x, y) __attribute__((format(printf, x, y)))
-+#else
-+#define FORMAT_ATTR(x, y)
-+#endif
-+
-+int FORMAT_ATTR(2, 3) dbuf_printf(DynBuf *s, const char *fmt, ...);
-+
- void dbuf_free(DynBuf *s);
- static inline BOOL dbuf_error(DynBuf *s) {
- return s->error;
-diff --git a/libregexp.c b/libregexp.c
-index 379bfc7..ad91f78 100644
---- a/libregexp.c
-+++ b/libregexp.c
-@@ -271,7 +271,7 @@ static int cr_canonicalize(CharRange *cr)
- }
-
- #ifdef DUMP_REOP
--static __maybe_unused void lre_dump_bytecode(const uint8_t *buf,
-+static MAYBE_UNUSED void lre_dump_bytecode(const uint8_t *buf,
- int buf_len)
- {
- int pos, len, opcode, bc_len, re_flags, i;
-@@ -427,7 +427,7 @@ static void re_emit_op_u16(REParseState *s, int op, uint32_t val)
- dbuf_put_u16(&s->byte_code, val);
- }
-
--static int __attribute__((format(printf, 2, 3))) re_parse_error(REParseState *s, const char *fmt, ...)
-+static int FORMAT_ATTR(2, 3) re_parse_error(REParseState *s, const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
-@@ -1472,7 +1472,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
- default:
- parse_class_atom:
- c = get_class_atom(s, cr, &p, FALSE);
-- if ((int)c < 0)
-+ if (c < 0)
- return -1;
- normal_char:
- last_atom_start = s->byte_code.size;
-@@ -1924,17 +1924,17 @@ static BOOL is_word_char(uint32_t c)
- #define GET_CHAR(c, cptr, cbuf_end) \
- do { \
- if (cbuf_type == 0) { \
-- c = *cptr++; \
-+ (c) = *(cptr)++; \
- } else { \
- uint32_t __c1; \
-- c = *(uint16_t *)cptr; \
-- cptr += 2; \
-- if (c >= 0xd800 && c < 0xdc00 && \
-- cbuf_type == 2 && cptr < cbuf_end) { \
-- __c1 = *(uint16_t *)cptr; \
-+ (c) = *(uint16_t *)(cptr); \
-+ (cptr) += 2; \
-+ if ((c) >= 0xd800 && (c) < 0xdc00 && \
-+ cbuf_type == 2 && (cptr) < (cbuf_end)) { \
-+ __c1 = *(uint16_t *)(cptr); \
- if (__c1 >= 0xdc00 && __c1 < 0xe000) { \
-- c = (((c & 0x3ff) << 10) | (__c1 & 0x3ff)) + 0x10000; \
-- cptr += 2; \
-+ (c) = ((((c) & 0x3ff) << 10) | (__c1 & 0x3ff)) + 0x10000; \
-+ (cptr) += 2; \
- } \
- } \
- } \
-@@ -1943,15 +1943,15 @@ static BOOL is_word_char(uint32_t c)
- #define PEEK_CHAR(c, cptr, cbuf_end) \
- do { \
- if (cbuf_type == 0) { \
-- c = cptr[0]; \
-+ (c) = (cptr)[0]; \
- } else { \
- uint32_t __c1; \
-- c = ((uint16_t *)cptr)[0]; \
-- if (c >= 0xd800 && c < 0xdc00 && \
-- cbuf_type == 2 && (cptr + 2) < cbuf_end) { \
-- __c1 = ((uint16_t *)cptr)[1]; \
-+ (c) = ((uint16_t *)(cptr))[0]; \
-+ if ((c) >= 0xd800 && (c) < 0xdc00 && \
-+ cbuf_type == 2 && ((cptr) + 2) < (cbuf_end)) { \
-+ __c1 = ((uint16_t *)(cptr))[1]; \
- if (__c1 >= 0xdc00 && __c1 < 0xe000) { \
-- c = (((c & 0x3ff) << 10) | (__c1 & 0x3ff)) + 0x10000; \
-+ (c) = ((((c) & 0x3ff) << 10) | (__c1 & 0x3ff)) + 0x10000; \
- } \
- } \
- } \
-@@ -1960,15 +1960,15 @@ static BOOL is_word_char(uint32_t c)
- #define PEEK_PREV_CHAR(c, cptr, cbuf_start) \
- do { \
- if (cbuf_type == 0) { \
-- c = cptr[-1]; \
-+ (c) = (cptr)[-1]; \
- } else { \
- uint32_t __c1; \
-- c = ((uint16_t *)cptr)[-1]; \
-- if (c >= 0xdc00 && c < 0xe000 && \
-- cbuf_type == 2 && (cptr - 4) >= cbuf_start) { \
-- __c1 = ((uint16_t *)cptr)[-2]; \
-+ (c) = ((uint16_t *)(cptr))[-1]; \
-+ if ((c) >= 0xdc00 && (c) < 0xe000 && \
-+ cbuf_type == 2 && ((cptr) - 4) >= (cbuf_start)) { \
-+ __c1 = ((uint16_t *)(cptr))[-2]; \
- if (__c1 >= 0xd800 && __c1 < 0xdc00 ) { \
-- c = (((__c1 & 0x3ff) << 10) | (c & 0x3ff)) + 0x10000; \
-+ (c) = (((__c1 & 0x3ff) << 10) | ((c) & 0x3ff)) + 0x10000; \
- } \
- } \
- } \
-@@ -1977,18 +1977,18 @@ static BOOL is_word_char(uint32_t c)
- #define GET_PREV_CHAR(c, cptr, cbuf_start) \
- do { \
- if (cbuf_type == 0) { \
-- cptr--; \
-- c = cptr[0]; \
-+ (cptr)--; \
-+ (c) = (cptr)[0]; \
- } else { \
- uint32_t __c1; \
-- cptr -= 2; \
-- c = ((uint16_t *)cptr)[0]; \
-- if (c >= 0xdc00 && c < 0xe000 && \
-- cbuf_type == 2 && cptr > cbuf_start) { \
-- __c1 = ((uint16_t *)cptr)[-1]; \
-+ (cptr) -= 2; \
-+ (c) = ((uint16_t *)(cptr))[0]; \
-+ if ((c) >= 0xdc00 && (c) < 0xe000 && \
-+ cbuf_type == 2 && (cptr) > (cbuf_start)) { \
-+ __c1 = ((uint16_t *)(cptr))[-1]; \
- if (__c1 >= 0xd800 && __c1 < 0xdc00 ) { \
-- cptr -= 2; \
-- c = (((__c1 & 0x3ff) << 10) | (c & 0x3ff)) + 0x10000; \
-+ (cptr) -= 2; \
-+ (c) = (((__c1 & 0x3ff) << 10) | ((c) & 0x3ff)) + 0x10000; \
- } \
- } \
- } \
-@@ -1997,15 +1997,15 @@ static BOOL is_word_char(uint32_t c)
- #define PREV_CHAR(cptr, cbuf_start) \
- do { \
- if (cbuf_type == 0) { \
-- cptr--; \
-+ (cptr)--; \
- } else { \
-- cptr -= 2; \
-+ (cptr) -= 2; \
- if (cbuf_type == 2) { \
-- c = ((uint16_t *)cptr)[0]; \
-- if (c >= 0xdc00 && c < 0xe000 && cptr > cbuf_start) { \
-- c = ((uint16_t *)cptr)[-1]; \
-+ c = ((uint16_t *)(cptr))[0]; \
-+ if (c >= 0xdc00 && c < 0xe000 && (cptr) > (cbuf_start)) { \
-+ c = ((uint16_t *)(cptr))[-1]; \
- if (c >= 0xd800 && c < 0xdc00) \
-- cptr -= 2; \
-+ (cptr) -= 2; \
- } \
- } \
- } \
-@@ -2049,7 +2049,7 @@ typedef struct {
-
- static int push_state(REExecContext *s,
- uint8_t **capture,
-- StackInt *stack, size_t stack_len,
-+ const StackInt *stack, size_t stack_len,
- const uint8_t *pc, const uint8_t *cptr,
- REExecStateEnum type, size_t count)
- {
-diff --git a/libunicode.c b/libunicode.c
-index 63c12a0..112da72 100644
---- a/libunicode.c
-+++ b/libunicode.c
-@@ -271,7 +271,7 @@ BOOL lre_is_case_ignorable(uint32_t c)
-
- /* character range */
-
--static __maybe_unused void cr_dump(CharRange *cr)
-+static maybe_unused void cr_dump(CharRange *cr)
- {
- int i;
- for(i = 0; i < cr->len; i++)
-@@ -1315,11 +1315,13 @@ static int unicode_prop_ops(CharRange *cr, ...)
- }
- }
- done:
-+ va_end(ap);
- assert(stack_len == 1);
- ret = cr_copy(cr, &stack[0]);
- cr_free(&stack[0]);
- return ret;
- fail:
-+ va_end(ap);
- for(i = 0; i < stack_len; i++)
- cr_free(&stack[i]);
- return -1;
-diff --git a/list.h b/list.h
-index 0a1bc5a..e7f51a9 100644
---- a/list.h
-+++ b/list.h
-@@ -46,7 +46,7 @@ static inline void init_list_head(struct list_head *head)
- }
-
- /* insert 'el' between 'prev' and 'next' */
--static inline void __list_add(struct list_head *el,
-+static inline void list_add_impl(struct list_head *el,
- struct list_head *prev, struct list_head *next)
- {
- prev->next = el;
-@@ -58,13 +58,13 @@ static inline void __list_add(struct list_head *el,
- /* add 'el' at the head of the list 'head' (= after element head) */
- static inline void list_add(struct list_head *el, struct list_head *head)
- {
-- __list_add(el, head, head->next);
-+ list_add_impl(el, head, head->next);
- }
-
- /* add 'el' at the end of the list 'head' (= before element head) */
- static inline void list_add_tail(struct list_head *el, struct list_head *head)
- {
-- __list_add(el, head->prev, head);
-+ list_add_impl(el, head->prev, head);
- }
-
- static inline void list_del(struct list_head *el)
-diff --git a/quickjs.c b/quickjs.c
-index 7916013..f90fb9e 100644
---- a/quickjs.c
-+++ b/quickjs.c
-@@ -28,7 +28,9 @@
- #include <inttypes.h>
- #include <string.h>
- #include <assert.h>
-+#ifndef _MSC_VER
- #include <sys/time.h>
-+#endif
- #include <time.h>
- #include <fenv.h>
- #include <math.h>
-@@ -40,6 +42,18 @@
- #include <malloc_np.h>
- #endif
-
-+#ifdef _MSC_VER
-+#include <intrin.h>
-+#include <windows.h>
-+#endif
-+
-+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
-+ || defined(__APPLE__)
-+#include <xlocale.h>
-+#else
-+#include <locale.h>
-+#endif
-+
- #include "cutils.h"
- #include "list.h"
- #include "quickjs.h"
-@@ -48,9 +62,9 @@
- #include "libbf.h"
- #endif
-
--#define OPTIMIZE 1
-+#define OPTIMIZE 0
- #define SHORT_OPCODES 1
--#if defined(EMSCRIPTEN)
-+#if defined(EMSCRIPTEN) || defined(_MSC_VER)
- #define DIRECT_DISPATCH 0
- #else
- #define DIRECT_DISPATCH 1
-@@ -69,7 +83,7 @@
-
- /* define to include Atomics.* operations which depend on the OS
- threads */
--#if !defined(EMSCRIPTEN)
-+#if !defined(EMSCRIPTEN) && !defined(_MSC_VER)
- #define CONFIG_ATOMICS
- #endif
-
-@@ -78,7 +92,6 @@
- #define CONFIG_STACK_CHECK
- #endif
-
--
- /* dump object free */
- //#define DUMP_FREE
- //#define DUMP_CLOSURE
-@@ -115,6 +128,25 @@
- #include <errno.h>
- #endif
-
-+static double safe_strtod(const char *restrict nptr, char **restrict endptr)
-+{
-+#if defined(_MSC_VER) || defined(__MINGW32__)
-+ _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
-+ setlocale(LC_NUMERIC, "C");
-+#else
-+ const locale_t tempLoc = newlocale(LC_NUMERIC_MASK, "C", 0);
-+ uselocale(tempLoc);
-+#endif
-+ double d = strtod(nptr, endptr);
-+#if defined(_MSC_VER) || defined(__MINGW32__)
-+ _configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
-+#else
-+ uselocale(LC_GLOBAL_LOCALE);
-+ freelocale(tempLoc);
-+#endif
-+ return d;
-+}
-+
- enum {
- /* classid tag */ /* union usage | properties */
- JS_CLASS_OBJECT = 1, /* must be first */
-@@ -204,7 +236,11 @@ typedef enum JSErrorEnum {
- #define JS_STACK_SIZE_MAX 65534
- #define JS_STRING_LEN_MAX ((1 << 30) - 1)
-
--#define __exception __attribute__((warn_unused_result))
-+#ifdef __GNUC__
-+#define warn_unused __attribute__((warn_unused_result))
-+#else
-+#define warn_unused
-+#endif
-
- typedef struct JSShape JSShape;
- typedef struct JSString JSString;
-@@ -362,8 +398,8 @@ typedef struct JSVarRef {
- union {
- JSGCObjectHeader header; /* must come first */
- struct {
-- int __gc_ref_count; /* corresponds to header.ref_count */
-- uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
-+ int _gc_ref_count; /* corresponds to header.ref_count */
-+ uint8_t _gc_mark; /* corresponds to header.mark/gc_obj_type */
-
- /* 0 : the JSVarRef is on the stack. header.link is an element
- of JSStackFrame.var_ref_list.
-@@ -455,8 +491,12 @@ struct JSContext {
- /* if NULL, eval is not supported */
- JSValue (*eval_internal)(JSContext *ctx, JSValueConst this_obj,
- const char *input, size_t input_len,
-- const char *filename, int flags, int scope_idx);
-+ const char *filename, int line, int flags, int scope_idx);
- void *user_opaque;
-+ ScopeLookup *scopeLookup;
-+ FoundUndefinedHandler *handleUndefined;
-+ FunctionEnteredHandler *handleFunctionEntered;
-+ FunctionExitedHandler *handleFunctionExited;
- };
-
- typedef union JSFloat64Union {
-@@ -867,8 +907,8 @@ struct JSObject {
- union {
- JSGCObjectHeader header;
- struct {
-- int __gc_ref_count; /* corresponds to header.ref_count */
-- uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
-+ int _gc_ref_count; /* corresponds to header.ref_count */
-+ uint8_t _gc_mark; /* corresponds to header.mark/gc_obj_type */
-
- uint8_t extensible : 1;
- uint8_t free_mark : 1; /* only used when freeing objects with cycles */
-@@ -950,7 +990,7 @@ struct JSObject {
- /* byte sizes: 40/48/72 */
- };
- enum {
-- __JS_ATOM_NULL = JS_ATOM_NULL,
-+ JS_ATOM_NULL_ = JS_ATOM_NULL,
- #define DEF(name, str) JS_ATOM_ ## name,
- #include "quickjs-atom.h"
- #undef DEF
-@@ -996,7 +1036,7 @@ enum OPCodeEnum {
- };
-
- static int JS_InitAtoms(JSRuntime *rt);
--static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
-+static JSAtom JS_NewAtomInitImpl(JSRuntime *rt, const char *str, int len,
- int atom_type);
- static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p);
- static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b);
-@@ -1017,24 +1057,23 @@ static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_o
- int argc, JSValueConst *argv);
- static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
- int argc, JSValueConst *argv);
--static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
-+static warn_unused int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
- JSValue val, BOOL is_array_ctor);
- static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
- JSValueConst val, int flags, int scope_idx);
--JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...);
--static __maybe_unused void JS_DumpAtoms(JSRuntime *rt);
--static __maybe_unused void JS_DumpString(JSRuntime *rt,
-+static maybe_unused void JS_DumpAtoms(JSRuntime *rt);
-+static maybe_unused void JS_DumpString(JSRuntime *rt,
- const JSString *p);
--static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt);
--static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p);
--static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p);
--static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
-+static maybe_unused void JS_DumpObjectHeader(JSRuntime *rt);
-+static maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p);
-+static maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p);
-+static maybe_unused void JS_DumpValueShort(JSRuntime *rt,
- JSValueConst val);
--static __maybe_unused void JS_DumpValue(JSContext *ctx, JSValueConst val);
--static __maybe_unused void JS_PrintValue(JSContext *ctx,
-+static maybe_unused void JS_DumpValue(JSContext *ctx, JSValueConst val);
-+static maybe_unused void JS_PrintValue(JSContext *ctx,
- const char *str,
- JSValueConst val);
--static __maybe_unused void JS_DumpShapes(JSRuntime *rt);
-+static maybe_unused void JS_DumpShapes(JSRuntime *rt);
- static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic);
- static void js_array_finalizer(JSRuntime *rt, JSValue val);
-@@ -1148,7 +1187,6 @@ static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
- BOOL allow_null_or_undefined);
- static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val);
- #endif
--JSValue JS_ThrowOutOfMemory(JSContext *ctx);
- static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx);
- static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj);
- static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
-@@ -1187,7 +1225,7 @@ static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func);
- static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
- const char *input, size_t input_len,
-- const char *filename, int flags, int scope_idx);
-+ const char *filename, int line, int flags, int scope_idx);
- static void js_free_module_def(JSContext *ctx, JSModuleDef *m);
- static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
- JS_MarkFunc *mark_func);
-@@ -1197,7 +1235,7 @@ static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref);
- static JSValue js_new_promise_capability(JSContext *ctx,
- JSValue *resolving_funcs,
- JSValueConst ctor);
--static __exception int perform_promise_then(JSContext *ctx,
-+static warn_unused int perform_promise_then(JSContext *ctx,
- JSValueConst promise,
- JSValueConst *resolve_reject,
- JSValueConst *cap_resolving_funcs);
-@@ -1222,9 +1260,9 @@ static void js_free_shape_null(JSRuntime *rt, JSShape *sh);
- static int js_shape_prepare_update(JSContext *ctx, JSObject *p,
- JSShapeProperty **pprs);
- static int init_shape_hash(JSRuntime *rt);
--static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
-+static warn_unused int js_get_length32(JSContext *ctx, uint32_t *pres,
- JSValueConst obj);
--static __exception int js_get_length64(JSContext *ctx, int64_t *pres,
-+static warn_unused int js_get_length64(JSContext *ctx, int64_t *pres,
- JSValueConst obj);
- static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len);
- static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
-@@ -1582,10 +1620,27 @@ static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
- return FALSE;
- }
- #else
--/* Note: OS and CPU dependent */
-+// Uses code from LLVM project.
- static inline uintptr_t js_get_stack_pointer(void)
- {
-+#ifdef _MSC_VER
-+ return (uintptr_t) _AddressOfReturnAddress();
-+#elif defined __has_builtin
-+#if __has_builtin(__builtin_frame_address)
- return (uintptr_t) __builtin_frame_address(0);
-+#endif
-+#elif defined __GNUC__
-+ return (uintptr_t) __builtin_frame_address(0);
-+#else
-+ char CharOnStack = 0;
-+ // The volatile store here is intended to escape the local variable, to
-+ // prevent the compiler from optimizing CharOnStack into anything other
-+ // than a char on the stack.
-+ //
-+ // Tested on: MSVC 2015 - 2019, GCC 4.9 - 9, Clang 3.2 - 9, ICC 13 - 19.
-+ char *volatile Ptr = &CharOnStack;
-+ return (uintptr_t) Ptr;
-+#endif
- }
-
- static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
-@@ -1980,6 +2035,7 @@ void JS_FreeRuntime(JSRuntime *rt)
- printf("Secondary object leaks: %d\n", count);
- }
- #endif
-+ fflush(stdout);
- assert(list_empty(&rt->gc_obj_list));
-
- /* free the classes */
-@@ -2386,7 +2442,7 @@ static inline BOOL is_math_mode(JSContext *ctx)
- /* return the max count from the hash size */
- #define JS_ATOM_COUNT_RESIZE(n) ((n) * 2)
-
--static inline BOOL __JS_AtomIsConst(JSAtom v)
-+static inline BOOL JS_AtomIsConst(JSAtom v)
- {
- #if defined(DUMP_LEAKS) && DUMP_LEAKS > 1
- return (int32_t)v <= 0;
-@@ -2395,17 +2451,17 @@ static inline BOOL __JS_AtomIsConst(JSAtom v)
- #endif
- }
-
--static inline BOOL __JS_AtomIsTaggedInt(JSAtom v)
-+static inline BOOL JS_AtomIsTaggedInt(JSAtom v)
- {
- return (v & JS_ATOM_TAG_INT) != 0;
- }
-
--static inline JSAtom __JS_AtomFromUInt32(uint32_t v)
-+static inline JSAtom JS_AtomFromUInt32(uint32_t v)
- {
- return v | JS_ATOM_TAG_INT;
- }
-
--static inline uint32_t __JS_AtomToUInt32(JSAtom atom)
-+static inline uint32_t JS_AtomToUInt32(JSAtom atom)
- {
- return atom & ~JS_ATOM_TAG_INT;
- }
-@@ -2485,7 +2541,7 @@ static uint32_t hash_string(const JSString *str, uint32_t h)
- return h;
- }
-
--static __maybe_unused void JS_DumpString(JSRuntime *rt,
-+static maybe_unused void JS_DumpString(JSRuntime *rt,
- const JSString *p)
- {
- int i, c, sep;
-@@ -2517,7 +2573,7 @@ static __maybe_unused void JS_DumpString(JSRuntime *rt,
- putchar(sep);
- }
-
--static __maybe_unused void JS_DumpAtoms(JSRuntime *rt)
-+static maybe_unused void JS_DumpAtoms(JSRuntime *rt)
- {
- JSAtomStruct *p;
- int h, i;
-@@ -2604,7 +2660,7 @@ static int JS_InitAtoms(JSRuntime *rt)
- else
- atom_type = JS_ATOM_TYPE_STRING;
- len = strlen(p);
-- if (__JS_NewAtomInit(rt, p, len, atom_type) == JS_ATOM_NULL)
-+ if (JS_NewAtomInitImpl(rt, p, len, atom_type) == JS_ATOM_NULL)
- return -1;
- p = p + len + 1;
- }
-@@ -2615,7 +2671,7 @@ static JSAtom JS_DupAtomRT(JSRuntime *rt, JSAtom v)
- {
- JSAtomStruct *p;
-
-- if (!__JS_AtomIsConst(v)) {
-+ if (!JS_AtomIsConst(v)) {
- p = rt->atom_array[v];
- p->header.ref_count++;
- }
-@@ -2627,7 +2683,7 @@ JSAtom JS_DupAtom(JSContext *ctx, JSAtom v)
- JSRuntime *rt;
- JSAtomStruct *p;
-
-- if (!__JS_AtomIsConst(v)) {
-+ if (!JS_AtomIsConst(v)) {
- rt = ctx->rt;
- p = rt->atom_array[v];
- p->header.ref_count++;
-@@ -2641,7 +2697,7 @@ static JSAtomKindEnum JS_AtomGetKind(JSContext *ctx, JSAtom v)
- JSAtomStruct *p;
-
- rt = ctx->rt;
-- if (__JS_AtomIsTaggedInt(v))
-+ if (JS_AtomIsTaggedInt(v))
- return JS_ATOM_KIND_STRING;
- p = rt->atom_array[v];
- switch(p->atom_type) {
-@@ -2687,7 +2743,7 @@ static JSAtom js_get_atom_index(JSRuntime *rt, JSAtomStruct *p)
-
- /* string case (internal). Return JS_ATOM_NULL if error. 'str' is
- freed. */
--static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type)
-+static JSAtom JS_NewAtomImpl(JSRuntime *rt, JSString *str, int atom_type)
- {
- uint32_t h, h1, i;
- JSAtomStruct *p;
-@@ -2702,7 +2758,7 @@ static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type)
- /* str is the atom, return its index */
- i = js_get_atom_index(rt, str);
- /* reduce string refcount and increase atom's unless constant */
-- if (__JS_AtomIsConst(i))
-+ if (JS_AtomIsConst(i))
- str->header.ref_count--;
- return i;
- }
-@@ -2718,7 +2774,7 @@ static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type)
- p->atom_type == atom_type &&
- p->len == len &&
- js_string_memcmp(p, str, len) == 0) {
-- if (!__JS_AtomIsConst(i))
-+ if (!JS_AtomIsConst(i))
- p->header.ref_count++;
- goto done;
- }
-@@ -2843,7 +2899,7 @@ static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type)
- }
-
- /* only works with zero terminated 8 bit strings */
--static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
-+static JSAtom JS_NewAtomInitImpl(JSRuntime *rt, const char *str, int len,
- int atom_type)
- {
- JSString *p;
-@@ -2852,10 +2908,10 @@ static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
- return JS_ATOM_NULL;
- memcpy(p->u.str8, str, len);
- p->u.str8[len] = '\0';
-- return __JS_NewAtom(rt, p, atom_type);
-+ return JS_NewAtomImpl(rt, p, atom_type);
- }
-
--static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len,
-+static JSAtom JS_FindAtom(JSRuntime *rt, const char *str, size_t len,
- int atom_type)
- {
- uint32_t h, h1, i;
-@@ -2872,7 +2928,7 @@ static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len,
- p->len == len &&
- p->is_wide_char == 0 &&
- memcmp(p->u.str8, str, len) == 0) {
-- if (!__JS_AtomIsConst(i))
-+ if (!JS_AtomIsConst(i))
- p->header.ref_count++;
- return i;
- }
-@@ -2924,7 +2980,7 @@ static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p)
- assert(rt->atom_count >= 0);
- }
-
--static void __JS_FreeAtom(JSRuntime *rt, uint32_t i)
-+static void JS_FreeAtomImpl(JSRuntime *rt, uint32_t i)
- {
- JSAtomStruct *p;
-
-@@ -2942,11 +2998,11 @@ static JSAtom JS_NewAtomStr(JSContext *ctx, JSString *p)
- if (is_num_string(&n, p)) {
- if (n <= JS_ATOM_MAX_INT) {
- js_free_string(rt, p);
-- return __JS_AtomFromUInt32(n);
-+ return JS_AtomFromUInt32(n);
- }
- }
- /* XXX: should generate an exception */
-- return __JS_NewAtom(rt, p, JS_ATOM_TYPE_STRING);
-+ return JS_NewAtomImpl(rt, p, JS_ATOM_TYPE_STRING);
- }
-
- JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len)
-@@ -2954,7 +3010,7 @@ JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len)
- JSValue val;
-
- if (len == 0 || !is_digit(*str)) {
-- JSAtom atom = __JS_FindAtom(ctx->rt, str, len, JS_ATOM_TYPE_STRING);
-+ JSAtom atom = JS_FindAtom(ctx->rt, str, len, JS_ATOM_TYPE_STRING);
- if (atom)
- return atom;
- }
-@@ -2972,7 +3028,7 @@ JSAtom JS_NewAtom(JSContext *ctx, const char *str)
- JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n)
- {
- if (n <= JS_ATOM_MAX_INT) {
-- return __JS_AtomFromUInt32(n);
-+ return JS_AtomFromUInt32(n);
- } else {
- char buf[11];
- JSValue val;
-@@ -2980,7 +3036,7 @@ JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n)
- val = JS_NewString(ctx, buf);
- if (JS_IsException(val))
- return JS_ATOM_NULL;
-- return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
-+ return JS_NewAtomImpl(ctx->rt, JS_VALUE_GET_STRING(val),
- JS_ATOM_TYPE_STRING);
- }
- }
-@@ -2988,7 +3044,7 @@ JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n)
- static JSAtom JS_NewAtomInt64(JSContext *ctx, int64_t n)
- {
- if ((uint64_t)n <= JS_ATOM_MAX_INT) {
-- return __JS_AtomFromUInt32((uint32_t)n);
-+ return JS_AtomFromUInt32((uint32_t)n);
- } else {
- char buf[24];
- JSValue val;
-@@ -2996,7 +3052,7 @@ static JSAtom JS_NewAtomInt64(JSContext *ctx, int64_t n)
- val = JS_NewString(ctx, buf);
- if (JS_IsException(val))
- return JS_ATOM_NULL;
-- return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
-+ return JS_NewAtomImpl(ctx->rt, JS_VALUE_GET_STRING(val),
- JS_ATOM_TYPE_STRING);
- }
- }
-@@ -3006,7 +3062,7 @@ static JSValue JS_NewSymbol(JSContext *ctx, JSString *p, int atom_type)
- {
- JSRuntime *rt = ctx->rt;
- JSAtom atom;
-- atom = __JS_NewAtom(rt, p, atom_type);
-+ atom = JS_NewAtomImpl(rt, p, atom_type);
- if (atom == JS_ATOM_NULL)
- return JS_ThrowOutOfMemory(ctx);
- return JS_MKPTR(JS_TAG_SYMBOL, rt->atom_array[atom]);
-@@ -3019,7 +3075,7 @@ static JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr,
- JSRuntime *rt = ctx->rt;
- JSString *p;
-
-- assert(!__JS_AtomIsTaggedInt(descr));
-+ assert(!JS_AtomIsTaggedInt(descr));
- assert(descr < rt->atom_size);
- p = rt->atom_array[descr];
- JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
-@@ -3032,8 +3088,8 @@ static JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr,
- static const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size,
- JSAtom atom)
- {
-- if (__JS_AtomIsTaggedInt(atom)) {
-- snprintf(buf, buf_size, "%u", __JS_AtomToUInt32(atom));
-+ if (JS_AtomIsTaggedInt(atom)) {
-+ snprintf(buf, buf_size, "%u", JS_AtomToUInt32(atom));
- } else {
- JSAtomStruct *p;
- assert(atom < rt->atom_size);
-@@ -3083,12 +3139,12 @@ static const char *JS_AtomGetStr(JSContext *ctx, char *buf, int buf_size, JSAtom
- return JS_AtomGetStrRT(ctx->rt, buf, buf_size, atom);
- }
-
--static JSValue __JS_AtomToValue(JSContext *ctx, JSAtom atom, BOOL force_string)
-+static JSValue JS_AtomToValueImpl(JSContext *ctx, JSAtom atom, BOOL force_string)
- {
- char buf[ATOM_GET_STR_BUF_SIZE];
-
-- if (__JS_AtomIsTaggedInt(atom)) {
-- snprintf(buf, sizeof(buf), "%u", __JS_AtomToUInt32(atom));
-+ if (JS_AtomIsTaggedInt(atom)) {
-+ snprintf(buf, sizeof(buf), "%u", JS_AtomToUInt32(atom));
- return JS_NewString(ctx, buf);
- } else {
- JSRuntime *rt = ctx->rt;
-@@ -3112,20 +3168,20 @@ static JSValue __JS_AtomToValue(JSContext *ctx, JSAtom atom, BOOL force_string)
-
- JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom)
- {
-- return __JS_AtomToValue(ctx, atom, FALSE);
-+ return JS_AtomToValueImpl(ctx, atom, FALSE);
- }
-
- JSValue JS_AtomToString(JSContext *ctx, JSAtom atom)
- {
-- return __JS_AtomToValue(ctx, atom, TRUE);
-+ return JS_AtomToValueImpl(ctx, atom, TRUE);
- }
-
- /* return TRUE if the atom is an array index (i.e. 0 <= index <=
- 2^32-2 and return its value */
- static BOOL JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom)
- {
-- if (__JS_AtomIsTaggedInt(atom)) {
-- *pval = __JS_AtomToUInt32(atom);
-+ if (JS_AtomIsTaggedInt(atom)) {
-+ *pval = JS_AtomToUInt32(atom);
- return TRUE;
- } else {
- JSRuntime *rt = ctx->rt;
-@@ -3156,8 +3212,8 @@ static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom)
- int c, len, ret;
- JSValue num, str;
-
-- if (__JS_AtomIsTaggedInt(atom))
-- return JS_NewInt32(ctx, __JS_AtomToUInt32(atom));
-+ if (JS_AtomIsTaggedInt(atom))
-+ return JS_NewInt32(ctx, JS_AtomToUInt32(atom));
- assert(atom < rt->atom_size);
- p1 = rt->atom_array[atom];
- if (p1->atom_type != JS_ATOM_TYPE_STRING)
-@@ -3199,7 +3255,7 @@ static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom)
- /* -0 case is specific */
- if (c == '0' && len == 2) {
- minus_zero:
-- return __JS_NewFloat64(ctx, -0.0);
-+ return JS_NewFloat64Impl(ctx, -0.0);
- }
- }
- if (!is_num(c)) {
-@@ -3244,14 +3300,14 @@ static int JS_AtomIsNumericIndex(JSContext *ctx, JSAtom atom)
-
- void JS_FreeAtom(JSContext *ctx, JSAtom v)
- {
-- if (!__JS_AtomIsConst(v))
-- __JS_FreeAtom(ctx->rt, v);
-+ if (!JS_AtomIsConst(v))
-+ JS_FreeAtomImpl(ctx->rt, v);
- }
-
- void JS_FreeAtomRT(JSRuntime *rt, JSAtom v)
- {
-- if (!__JS_AtomIsConst(v))
-- __JS_FreeAtom(rt, v);
-+ if (!JS_AtomIsConst(v))
-+ JS_FreeAtomImpl(rt, v);
- }
-
- /* return TRUE if 'v' is a symbol with a string description */
-@@ -3261,7 +3317,7 @@ static BOOL JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v)
- JSAtomStruct *p;
-
- rt = ctx->rt;
-- if (__JS_AtomIsTaggedInt(v))
-+ if (JS_AtomIsTaggedInt(v))
- return FALSE;
- p = rt->atom_array[v];
- return (((p->atom_type == JS_ATOM_TYPE_SYMBOL &&
-@@ -3270,7 +3326,7 @@ static BOOL JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v)
- !(p->len == 0 && p->is_wide_char != 0));
- }
-
--static __maybe_unused void print_atom(JSContext *ctx, JSAtom atom)
-+static maybe_unused void print_atom(JSContext *ctx, JSAtom atom)
- {
- char buf[ATOM_GET_STR_BUF_SIZE];
- const char *p;
-@@ -3445,9 +3501,9 @@ int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def)
- JSAtom name;
-
- len = strlen(class_def->class_name);
-- name = __JS_FindAtom(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
-+ name = JS_FindAtom(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
- if (name == JS_ATOM_NULL) {
-- name = __JS_NewAtomInit(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
-+ name = JS_NewAtomInitImpl(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
- if (name == JS_ATOM_NULL)
- return -1;
- }
-@@ -4614,7 +4670,7 @@ static int add_shape_property(JSContext *ctx, JSShape **psh,
- pr = &prop[sh->prop_count++];
- pr->atom = JS_DupAtom(ctx, atom);
- pr->flags = prop_flags;
-- sh->has_small_array_index |= __JS_AtomIsTaggedInt(atom);
-+ sh->has_small_array_index |= JS_AtomIsTaggedInt(atom);
- /* add in hash table */
- hash_mask = sh->prop_hash_mask;
- h = atom & hash_mask;
-@@ -4675,7 +4731,7 @@ static JSShape *find_hashed_shape_prop(JSRuntime *rt, JSShape *sh,
- return NULL;
- }
-
--static __maybe_unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh)
-+static maybe_unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh)
- {
- char atom_buf[ATOM_GET_STR_BUF_SIZE];
- int j;
-@@ -4691,7 +4747,7 @@ static __maybe_unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh)
- printf("\n");
- }
-
--static __maybe_unused void JS_DumpShapes(JSRuntime *rt)
-+static maybe_unused void JS_DumpShapes(JSRuntime *rt)
- {
- int i;
- JSShape *sh;
-@@ -5471,7 +5527,7 @@ static void free_zero_refcount(JSRuntime *rt)
- }
-
- /* called with the ref_count of 'v' reaches zero. */
--void __JS_FreeValueRT(JSRuntime *rt, JSValue v)
-+static void JS_FreeValueRTImpl(JSRuntime *rt, JSValue v)
- {
- uint32_t tag = JS_VALUE_GET_TAG(v);
-
-@@ -5546,9 +5602,9 @@ void __JS_FreeValueRT(JSRuntime *rt, JSValue v)
- }
- }
-
--void __JS_FreeValue(JSContext *ctx, JSValue v)
-+static void JS_FreeValueImpl(JSContext *ctx, JSValue v)
- {
-- __JS_FreeValueRT(ctx->rt, v);
-+ JS_FreeValueRTImpl(ctx->rt, v);
- }
-
- /* garbage collection */
-@@ -6469,7 +6525,7 @@ static const char *get_func_name(JSContext *ctx, JSValueConst func)
-
- /* if filename != NULL, an additional level is added with the filename
- and line number information (used for parse error). */
--static void build_backtrace(JSContext *ctx, JSValueConst error_obj,
-+void build_backtrace(JSContext *ctx, JSValueConst error_obj,
- const char *filename, int line_num,
- int backtrace_flags)
- {
-@@ -6569,7 +6625,7 @@ JSValue JS_NewError(JSContext *ctx)
- static JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num,
- const char *fmt, va_list ap, BOOL add_backtrace)
- {
-- char buf[256];
-+ char buf[8192];
- JSValue obj, ret;
-
- vsnprintf(buf, sizeof(buf), fmt, ap);
-@@ -6604,7 +6660,7 @@ static JSValue JS_ThrowError(JSContext *ctx, JSErrorEnum error_num,
- return JS_ThrowError2(ctx, error_num, fmt, ap, add_backtrace);
- }
-
--JSValue __attribute__((format(printf, 2, 3))) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...)
-+JSValue FORMAT_ATTR(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...)
- {
- JSValue val;
- va_list ap;
-@@ -6615,7 +6671,7 @@ JSValue __attribute__((format(printf, 2, 3))) JS_ThrowSyntaxError(JSContext *ctx
- return val;
- }
-
--JSValue __attribute__((format(printf, 2, 3))) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...)
-+JSValue FORMAT_ATTR(2, 3) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...)
- {
- JSValue val;
- va_list ap;
-@@ -6626,7 +6682,7 @@ JSValue __attribute__((format(printf, 2, 3))) JS_ThrowTypeError(JSContext *ctx,
- return val;
- }
-
--static int __attribute__((format(printf, 3, 4))) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, const char *fmt, ...)
-+static int FORMAT_ATTR(3, 4) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, const char *fmt, ...)
- {
- va_list ap;
-
-@@ -6642,7 +6698,7 @@ static int __attribute__((format(printf, 3, 4))) JS_ThrowTypeErrorOrFalse(JSCont
- }
-
- /* never use it directly */
--static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
-+static JSValue FORMAT_ATTR(3, 4) JS_ThrowTypeErrorAtomImpl(JSContext *ctx, JSAtom atom, const char *fmt, ...)
- {
- char buf[ATOM_GET_STR_BUF_SIZE];
- return JS_ThrowTypeError(ctx, fmt,
-@@ -6650,7 +6706,7 @@ static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowTypeErrorAtom(JSC
- }
-
- /* never use it directly */
--static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
-+static JSValue FORMAT_ATTR(3, 4) JS_ThrowSyntaxErrorAtomImpl(JSContext *ctx, JSAtom atom, const char *fmt, ...)
- {
- char buf[ATOM_GET_STR_BUF_SIZE];
- return JS_ThrowSyntaxError(ctx, fmt,
-@@ -6659,8 +6715,8 @@ static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowSyntaxErrorAtom(J
-
- /* %s is replaced by 'atom'. The macro is used so that gcc can check
- the format string. */
--#define JS_ThrowTypeErrorAtom(ctx, fmt, atom) __JS_ThrowTypeErrorAtom(ctx, atom, fmt, "")
--#define JS_ThrowSyntaxErrorAtom(ctx, fmt, atom) __JS_ThrowSyntaxErrorAtom(ctx, atom, fmt, "")
-+#define JS_ThrowTypeErrorAtom(ctx, fmt, atom) JS_ThrowTypeErrorAtomImpl(ctx, atom, fmt, "")
-+#define JS_ThrowSyntaxErrorAtom(ctx, fmt, atom) JS_ThrowSyntaxErrorAtomImpl(ctx, atom, fmt, "")
-
- static int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom)
- {
-@@ -6673,7 +6729,7 @@ static int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom)
- }
- }
-
--JSValue __attribute__((format(printf, 2, 3))) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...)
-+JSValue FORMAT_ATTR(2, 3) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...)
- {
- JSValue val;
- va_list ap;
-@@ -6684,7 +6740,7 @@ JSValue __attribute__((format(printf, 2, 3))) JS_ThrowReferenceError(JSContext *
- return val;
- }
-
--JSValue __attribute__((format(printf, 2, 3))) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...)
-+JSValue FORMAT_ATTR(2, 3) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...)
- {
- JSValue val;
- va_list ap;
-@@ -6695,7 +6751,7 @@ JSValue __attribute__((format(printf, 2, 3))) JS_ThrowRangeError(JSContext *ctx,
- return val;
- }
-
--JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...)
-+JSValue FORMAT_ATTR(2, 3) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...)
- {
- JSValue val;
- va_list ap;
-@@ -6770,7 +6826,7 @@ static JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id)
- return JS_ThrowTypeErrorAtom(ctx, "%s object expected", name);
- }
-
--static no_inline __exception int __js_poll_interrupts(JSContext *ctx)
-+static no_inline warn_unused int js_poll_interrupts_impl(JSContext *ctx)
- {
- JSRuntime *rt = ctx->rt;
- ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT;
-@@ -6785,10 +6841,10 @@ static no_inline __exception int __js_poll_interrupts(JSContext *ctx)
- return 0;
- }
-
--static inline __exception int js_poll_interrupts(JSContext *ctx)
-+static inline warn_unused int js_poll_interrupts(JSContext *ctx)
- {
- if (unlikely(--ctx->interrupt_counter <= 0)) {
-- return __js_poll_interrupts(ctx);
-+ return js_poll_interrupts_impl(ctx);
- } else {
- return 0;
- }
-@@ -7092,9 +7148,9 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
- case JS_TAG_STRING:
- {
- JSString *p1 = JS_VALUE_GET_STRING(obj);
-- if (__JS_AtomIsTaggedInt(prop)) {
-+ if (JS_AtomIsTaggedInt(prop)) {
- uint32_t idx, ch;
-- idx = __JS_AtomToUInt32(prop);
-+ idx = JS_AtomToUInt32(prop);
- if (idx < p1->len) {
- if (p1->is_wide_char)
- ch = p1->u.str16[idx];
-@@ -7144,14 +7200,16 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
- continue;
- }
- } else {
-+ if (JS_IsUndefined(pr->u.value) && ctx->handleUndefined)
-+ ctx->handleUndefined(ctx);
- return JS_DupValue(ctx, pr->u.value);
- }
- }
- if (unlikely(p->is_exotic)) {
- /* exotic behaviors */
- if (p->fast_array) {
-- if (__JS_AtomIsTaggedInt(prop)) {
-- uint32_t idx = __JS_AtomToUInt32(prop);
-+ if (JS_AtomIsTaggedInt(prop)) {
-+ uint32_t idx = JS_AtomToUInt32(prop);
- if (idx < p->u.array.count) {
- /* we avoid duplicating the code */
- return JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
-@@ -7242,7 +7300,7 @@ static int JS_DefinePrivateField(JSContext *ctx, JSValueConst obj,
- JS_ThrowTypeErrorNotASymbol(ctx);
- goto fail;
- }
-- prop = js_symbol_to_atom(ctx, (JSValue)name);
-+ prop = js_symbol_to_atom(ctx, name);
- p = JS_VALUE_GET_OBJ(obj);
- prs = find_own_property(&pr, p, prop);
- if (prs) {
-@@ -7273,7 +7331,7 @@ static JSValue JS_GetPrivateField(JSContext *ctx, JSValueConst obj,
- /* safety check */
- if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL))
- return JS_ThrowTypeErrorNotASymbol(ctx);
-- prop = js_symbol_to_atom(ctx, (JSValue)name);
-+ prop = js_symbol_to_atom(ctx, name);
- p = JS_VALUE_GET_OBJ(obj);
- prs = find_own_property(&pr, p, prop);
- if (!prs) {
-@@ -7300,7 +7358,7 @@ static int JS_SetPrivateField(JSContext *ctx, JSValueConst obj,
- JS_ThrowTypeErrorNotASymbol(ctx);
- goto fail;
- }
-- prop = js_symbol_to_atom(ctx, (JSValue)name);
-+ prop = js_symbol_to_atom(ctx, name);
- p = JS_VALUE_GET_OBJ(obj);
- prs = find_own_property(&pr, p, prop);
- if (!prs) {
-@@ -7390,7 +7448,7 @@ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func)
- if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
- goto not_obj;
- p = JS_VALUE_GET_OBJ(obj);
-- prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, (JSValue)brand));
-+ prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, brand));
- if (!prs) {
- JS_ThrowTypeError(ctx, "invalid brand on object");
- return -1;
-@@ -7445,7 +7503,7 @@ static void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len)
-
- /* return < 0 in case if exception, 0 if OK. ptab and its atoms must
- be freed by the user. */
--static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
-+static int warn_unused JS_GetOwnPropertyNamesInternal(JSContext *ctx,
- JSPropertyEnum **ptab,
- uint32_t *plen,
- JSObject *p, int flags)
-@@ -7595,7 +7653,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
- len = js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
- add_array_keys:
- for(i = 0; i < len; i++) {
-- tab_atom[num_index].atom = __JS_AtomFromUInt32(i);
-+ tab_atom[num_index].atom = JS_AtomFromUInt32(i);
- if (tab_atom[num_index].atom == JS_ATOM_NULL) {
- js_free_prop_enum(ctx, tab_atom, num_index);
- return -1;
-@@ -7703,9 +7761,9 @@ retry:
- if (p->is_exotic) {
- if (p->fast_array) {
- /* specific case for fast arrays */
-- if (__JS_AtomIsTaggedInt(prop)) {
-+ if (JS_AtomIsTaggedInt(prop)) {
- uint32_t idx;
-- idx = __JS_AtomToUInt32(prop);
-+ idx = JS_AtomToUInt32(prop);
- if (idx < p->u.array.count) {
- if (desc) {
- desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE |
-@@ -7825,7 +7883,7 @@ JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
- if (tag == JS_TAG_INT &&
- (uint32_t)JS_VALUE_GET_INT(val) <= JS_ATOM_MAX_INT) {
- /* fast path for integer values */
-- atom = __JS_AtomFromUInt32(JS_VALUE_GET_INT(val));
-+ atom = JS_AtomFromUInt32(JS_VALUE_GET_INT(val));
- } else if (tag == JS_TAG_SYMBOL) {
- JSAtomStruct *p = JS_VALUE_GET_PTR(val);
- atom = JS_DupAtom(ctx, js_get_atom_index(ctx->rt, p));
-@@ -7856,7 +7914,7 @@ static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
- /* fast path for array access */
- p = JS_VALUE_GET_OBJ(this_obj);
- idx = JS_VALUE_GET_INT(prop);
-- len = (uint32_t)p->u.array.count;
-+ len = p->u.array.count;
- if (unlikely(idx >= len))
- goto slow_path;
- switch(p->class_id) {
-@@ -7883,9 +7941,9 @@ static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
- return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]);
- #endif
- case JS_CLASS_FLOAT32_ARRAY:
-- return __JS_NewFloat64(ctx, p->u.array.u.float_ptr[idx]);
-+ return JS_NewFloat64Impl(ctx, p->u.array.u.float_ptr[idx]);
- case JS_CLASS_FLOAT64_ARRAY:
-- return __JS_NewFloat64(ctx, p->u.array.u.double_ptr[idx]);
-+ return JS_NewFloat64Impl(ctx, p->u.array.u.double_ptr[idx]);
- default:
- goto slow_path;
- }
-@@ -7920,7 +7978,7 @@ static int JS_TryGetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx,
-
- if (likely((uint64_t)idx <= JS_ATOM_MAX_INT)) {
- /* fast path */
-- present = JS_HasProperty(ctx, obj, __JS_AtomFromUInt32(idx));
-+ present = JS_HasProperty(ctx, obj, JS_AtomFromUInt32(idx));
- if (present > 0) {
- val = JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx));
- if (unlikely(JS_IsException(val)))
-@@ -8017,7 +8075,7 @@ static JSProperty *add_property(JSContext *ctx,
-
- /* can be called on Array or Arguments objects. return < 0 if
- memory alloc error. */
--static no_inline __exception int convert_fast_array_to_array(JSContext *ctx,
-+static no_inline warn_unused int convert_fast_array_to_array(JSContext *ctx,
- JSObject *p)
- {
- JSProperty *pr;
-@@ -8039,8 +8097,8 @@ static no_inline __exception int convert_fast_array_to_array(JSContext *ctx,
- tab = p->u.array.u.values;
- for(i = 0; i < len; i++) {
- /* add_property cannot fail here but
-- __JS_AtomFromUInt32(i) fails for i > INT32_MAX */
-- pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E);
-+ JS_AtomFromUInt32(i) fails for i > INT32_MAX */
-+ pr = add_property(ctx, p, JS_AtomFromUInt32(i), JS_PROP_C_W_E);
- pr->u.value = *tab++;
- }
- js_free(ctx, p->u.array.u.values);
-@@ -8145,7 +8203,7 @@ static int call_setter(JSContext *ctx, JSObject *setter,
- func = JS_MKPTR(JS_TAG_OBJECT, setter);
- /* Note: the field could be removed in the setter */
- func = JS_DupValue(ctx, func);
-- ret = JS_CallFree(ctx, func, this_obj, 1, (JSValueConst *)&val);
-+ ret = JS_CallFree(ctx, func, this_obj, 1, &val);
- JS_FreeValue(ctx, val);
- if (JS_IsException(ret))
- return -1;
-@@ -8489,8 +8547,8 @@ retry:
- for(;;) {
- if (p1->is_exotic) {
- if (p1->fast_array) {
-- if (__JS_AtomIsTaggedInt(prop)) {
-- uint32_t idx = __JS_AtomToUInt32(prop);
-+ if (JS_AtomIsTaggedInt(prop)) {
-+ uint32_t idx = JS_AtomToUInt32(prop);
- if (idx < p1->u.array.count) {
- if (unlikely(p == p1))
- return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val, flags);
-@@ -8610,8 +8668,8 @@ retry:
-
- if (p->is_exotic) {
- if (p->class_id == JS_CLASS_ARRAY && p->fast_array &&
-- __JS_AtomIsTaggedInt(prop)) {
-- uint32_t idx = __JS_AtomToUInt32(prop);
-+ JS_AtomIsTaggedInt(prop)) {
-+ uint32_t idx = JS_AtomToUInt32(prop);
- if (idx == p->u.array.count) {
- /* fast case */
- return add_fast_array_element(ctx, p, val, flags);
-@@ -8662,7 +8720,7 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
- JSShape *sh1;
-
- /* fast path to add an element to the array */
-- if (idx != (uint32_t)p->u.array.count ||
-+ if (idx != p->u.array.count ||
- !p->fast_array || !p->extensible)
- goto slow_path;
- /* check if prototype chain has a numeric property */
-@@ -8837,8 +8895,8 @@ static int JS_CreateProperty(JSContext *ctx, JSObject *p,
- uint32_t idx, len;
-
- if (p->fast_array) {
-- if (__JS_AtomIsTaggedInt(prop)) {
-- idx = __JS_AtomToUInt32(prop);
-+ if (JS_AtomIsTaggedInt(prop)) {
-+ idx = JS_AtomToUInt32(prop);
- if (idx == p->u.array.count) {
- if (!p->extensible)
- goto not_extensible;
-@@ -9042,7 +9100,7 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
- return -1;
- }
- /* this code relies on the fact that Uint32 are never allocated */
-- val = (JSValueConst)JS_NewUint32(ctx, array_length);
-+ val = JS_NewUint32(ctx, array_length);
- /* prs may have been modified */
- prs = find_own_property(&pr, p, prop);
- assert(prs != NULL);
-@@ -9214,8 +9272,8 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
- uint32_t idx;
- uint32_t prop_flags;
- if (p->class_id == JS_CLASS_ARRAY) {
-- if (__JS_AtomIsTaggedInt(prop)) {
-- idx = __JS_AtomToUInt32(prop);
-+ if (JS_AtomIsTaggedInt(prop)) {
-+ idx = JS_AtomToUInt32(prop);
- if (idx < p->u.array.count) {
- prop_flags = get_prop_flags(flags, JS_PROP_C_W_E);
- if (prop_flags != JS_PROP_C_W_E)
-@@ -9238,7 +9296,7 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
- JSValue num;
- int ret;
-
-- if (!__JS_AtomIsTaggedInt(prop)) {
-+ if (!JS_AtomIsTaggedInt(prop)) {
- /* slow path with to handle all numeric indexes */
- num = JS_AtomIsNumericIndex1(ctx, prop);
- if (JS_IsUndefined(num))
-@@ -9259,10 +9317,10 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
- if (ret) {
- return JS_ThrowTypeErrorOrFalse(ctx, flags, "negative index in typed array");
- }
-- if (!__JS_AtomIsTaggedInt(prop))
-+ if (!JS_AtomIsTaggedInt(prop))
- goto typed_array_oob;
- }
-- idx = __JS_AtomToUInt32(prop);
-+ idx = JS_AtomToUInt32(prop);
- /* if the typed array is detached, p->u.array.count = 0 */
- if (idx >= typed_array_get_length(ctx, p)) {
- typed_array_oob:
-@@ -9563,6 +9621,11 @@ static JSValue JS_GetGlobalVar(JSContext *ctx, JSAtom prop,
- return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
- return JS_DupValue(ctx, pr->u.value);
- }
-+ if (ctx->scopeLookup) {
-+ struct LookupResult result = ctx->scopeLookup(ctx, prop);
-+ if (result.useResult)
-+ return result.value;
-+ }
- return JS_GetPropertyInternal(ctx, ctx->global_obj, prop,
- ctx->global_obj, throw_ref_error);
- }
-@@ -9658,6 +9721,15 @@ static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val,
- flags = JS_PROP_THROW_STRICT;
- if (is_strict_mode(ctx))
- flags |= JS_PROP_NO_ADD;
-+
-+ if (ctx->scopeLookup) {
-+ struct LookupResult result = ctx->scopeLookup(ctx, prop);
-+ if (result.useResult) {
-+ JS_FreeValue(ctx, result.value);
-+ return JS_SetPropertyInternal(ctx, result.scope, prop, val, flags);
-+ }
-+ }
-+
- return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags);
- }
-
-@@ -9693,7 +9765,7 @@ int JS_DeletePropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, int fl
-
- if ((uint64_t)idx <= JS_ATOM_MAX_INT) {
- /* fast path for fast arrays */
-- return JS_DeleteProperty(ctx, obj, __JS_AtomFromUInt32(idx), flags);
-+ return JS_DeleteProperty(ctx, obj, JS_AtomFromUInt32(idx), flags);
- }
- prop = JS_NewAtomInt64(ctx, idx);
- if (prop == JS_ATOM_NULL)
-@@ -9853,7 +9925,7 @@ static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint)
- break;
- }
- arg = JS_AtomToString(ctx, atom);
-- ret = JS_CallFree(ctx, method, val, 1, (JSValueConst *)&arg);
-+ ret = JS_CallFree(ctx, method, val, 1, &arg);
- JS_FreeValue(ctx, arg);
- if (JS_IsException(ret))
- goto exception;
-@@ -10057,7 +10129,7 @@ static double js_strtod(const char *p, int radix, BOOL is_float)
- if (is_neg)
- d = -d;
- } else {
-- d = strtod(p, NULL);
-+ d = safe_strtod(p, NULL);
- }
- return d;
- }
-@@ -10237,7 +10309,7 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
- } else
- #endif
- {
-- double d = 1.0 / 0.0;
-+ double d = INFINITY;
- if (is_neg)
- d = -d;
- val = JS_NewFloat64(ctx, d);
-@@ -10270,11 +10342,8 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
- ((*p == 'p' || *p == 'P') && (radix == 2 || radix == 8 || radix == 16)))) {
- const char *p1 = p + 1;
- is_float = TRUE;
-- if (*p1 == '+') {
-- p1++;
-- } else if (*p1 == '-') {
-+ if (*p1 == '+' || *p1 == '-')
- p1++;
-- }
- if (is_digit((uint8_t)*p1)) {
- p = p1 + 1;
- while (is_digit((uint8_t)*p) || (*p == sep && is_digit((uint8_t)p[1])))
-@@ -10509,7 +10578,7 @@ static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val)
- return JS_ToNumericFree(ctx, JS_DupValue(ctx, val));
- }
-
--static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres,
-+static warn_unused int JS_ToFloat64FreeImpl(JSContext *ctx, double *pres,
- JSValue val)
- {
- double d;
-@@ -10560,7 +10629,7 @@ static inline int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val)
- *pres = JS_VALUE_GET_FLOAT64(val);
- return 0;
- } else {
-- return __JS_ToFloat64Free(ctx, pres, val);
-+ return JS_ToFloat64FreeImpl(ctx, pres, val);
- }
- }
-
-@@ -10575,7 +10644,7 @@ static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val)
- }
-
- /* same as JS_ToNumber() but return 0 in case of NaN/Undefined */
--static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
-+static maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
- {
- uint32_t tag;
- JSValue ret;
-@@ -10990,7 +11059,7 @@ static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val)
- return 0;
- }
-
--static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
-+static warn_unused int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
- JSValue val, BOOL is_array_ctor)
- {
- uint32_t tag, len;
-@@ -11092,7 +11161,7 @@ int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val)
-
- /* convert a value to a length between 0 and MAX_SAFE_INTEGER.
- return -1 for exception */
--static __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen,
-+static warn_unused int JS_ToLengthFree(JSContext *ctx, int64_t *plen,
- JSValue val)
- {
- int res = JS_ToInt64Clamp(ctx, plen, val, 0, MAX_SAFE_INTEGER, 0);
-@@ -11338,7 +11407,7 @@ static int js_ecvt(double d, int n_digits, int *decpt, int *sign, char *buf,
- n_digits = (n_digits_min + n_digits_max) / 2;
- js_ecvt1(d, n_digits, decpt, sign, buf, FE_TONEAREST,
- buf_tmp, sizeof(buf_tmp));
-- if (strtod(buf_tmp, NULL) == d) {
-+ if (safe_strtod(buf_tmp, NULL) == d) {
- /* no need to keep the trailing zeros */
- while (n_digits >= 2 && buf[n_digits - 1] == '0')
- n_digits--;
-@@ -11700,14 +11769,14 @@ static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1)
- return JS_EXCEPTION;
- }
-
--static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt)
-+static maybe_unused void JS_DumpObjectHeader(JSRuntime *rt)
- {
- printf("%14s %4s %4s %14s %10s %s\n",
- "ADDRESS", "REFS", "SHRF", "PROTO", "CLASS", "PROPS");
- }
-
- /* for debug only: dump an object without side effect */
--static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
-+static maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
- {
- uint32_t i;
- char atom_buf[ATOM_GET_STR_BUF_SIZE];
-@@ -11784,7 +11853,7 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
- printf("[autoinit %p %d %p]",
- (void *)js_autoinit_get_realm(pr),
- js_autoinit_get_id(pr),
-- (void *)pr->u.init.opaque);
-+ pr->u.init.opaque);
- } else {
- JS_DumpValueShort(rt, pr->u.value);
- }
-@@ -11813,7 +11882,7 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
- printf("\n");
- }
-
--static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p)
-+static maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p)
- {
- if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
- JS_DumpObject(rt, (JSObject *)p);
-@@ -11845,7 +11914,7 @@ static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p)
- }
- }
-
--static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
-+static maybe_unused void JS_DumpValueShort(JSRuntime *rt,
- JSValueConst val)
- {
- uint32_t tag = JS_VALUE_GET_NORM_TAG(val);
-@@ -11950,13 +12019,13 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
- }
- }
-
--static __maybe_unused void JS_DumpValue(JSContext *ctx,
-+static maybe_unused void JS_DumpValue(JSContext *ctx,
- JSValueConst val)
- {
- JS_DumpValueShort(ctx->rt, val);
- }
-
--static __maybe_unused void JS_PrintValue(JSContext *ctx,
-+static maybe_unused void JS_PrintValue(JSContext *ctx,
- const char *str,
- JSValueConst val)
- {
-@@ -12439,7 +12508,7 @@ static JSObject *find_binary_op(JSBinaryOperatorDef *def,
-
- /* return -1 if exception, 0 if no operator overloading, 1 if
- overloaded operator called */
--static __exception int js_call_binary_op_fallback(JSContext *ctx,
-+static WARN_UNUSED int js_call_binary_op_fallback(JSContext *ctx,
- JSValue *pret,
- JSValueConst op1,
- JSValueConst op2,
-@@ -12568,7 +12637,7 @@ static __exception int js_call_binary_op_fallback(JSContext *ctx,
-
- /* try to call the operation on the operatorSet field of 'obj'. Only
- used for "/" and "**" on the BigInt prototype in math mode */
--static __exception int js_call_binary_op_simple(JSContext *ctx,
-+static WARN_UNUSED int js_call_binary_op_simple(JSContext *ctx,
- JSValue *pret,
- JSValueConst obj,
- JSValueConst op1,
-@@ -12625,7 +12694,7 @@ static __exception int js_call_binary_op_simple(JSContext *ctx,
-
- /* return -1 if exception, 0 if no operator overloading, 1 if
- overloaded operator called */
--static __exception int js_call_unary_op_fallback(JSContext *ctx,
-+static WARN_UNUSED int js_call_unary_op_fallback(JSContext *ctx,
- JSValue *pret,
- JSValueConst op1,
- OPCodeEnum op)
-@@ -12835,7 +12904,7 @@ static int js_unary_arith_bigdecimal(JSContext *ctx,
- return 0;
- }
-
--static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
-+static no_inline WARN_UNUSED int js_unary_arith_slow(JSContext *ctx,
- JSValue *sp,
- OPCodeEnum op)
- {
-@@ -12933,7 +13002,7 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
- return -1;
- }
-
--static __exception int js_post_inc_slow(JSContext *ctx,
-+static WARN_UNUSED int js_post_inc_slow(JSContext *ctx,
- JSValue *sp, OPCodeEnum op)
- {
- JSValue op1;
-@@ -13288,7 +13357,7 @@ static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op,
- return -1;
- }
-
--static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
-+static no_inline WARN_UNUSED int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
- OPCodeEnum op)
- {
- JSValue op1, op2, res;
-@@ -13452,7 +13521,7 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s
- return -1;
- }
-
--static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
-+static no_inline WARN_UNUSED int js_add_slow(JSContext *ctx, JSValue *sp)
- {
- JSValue op1, op2, res;
- uint32_t tag1, tag2;
-@@ -13566,7 +13635,7 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
- return -1;
- }
-
--static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
-+static no_inline WARN_UNUSED int js_binary_logic_slow(JSContext *ctx,
- JSValue *sp,
- OPCodeEnum op)
- {
-@@ -13916,7 +13985,7 @@ static BOOL tag_is_number(uint32_t tag)
- tag == JS_TAG_BIG_DECIMAL);
- }
-
--static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
-+static no_inline WARN_UNUSED int js_eq_slow(JSContext *ctx, JSValue *sp,
- BOOL is_neq)
- {
- JSValue op1, op2, ret;
-@@ -14192,7 +14261,7 @@ int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
- return -1;
- }
-
--static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
-+static no_inline warn_unused int js_unary_arith_slow(JSContext *ctx,
- JSValue *sp,
- OPCodeEnum op)
- {
-@@ -14224,7 +14293,7 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
- }
-
- /* specific case necessary for correct return value semantics */
--static __exception int js_post_inc_slow(JSContext *ctx,
-+static warn_unused int js_post_inc_slow(JSContext *ctx,
- JSValue *sp, OPCodeEnum op)
- {
- JSValue op1;
-@@ -14241,7 +14310,7 @@ static __exception int js_post_inc_slow(JSContext *ctx,
- return 0;
- }
-
--static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
-+static no_inline warn_unused int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
- OPCodeEnum op)
- {
- JSValue op1, op2;
-@@ -14283,7 +14352,7 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s
- return -1;
- }
-
--static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
-+static no_inline warn_unused int js_add_slow(JSContext *ctx, JSValue *sp)
- {
- JSValue op1, op2;
- uint32_t tag1, tag2;
-@@ -14331,7 +14400,7 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
- return -1;
- }
-
--static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
-+static no_inline warn_unused int js_binary_logic_slow(JSContext *ctx,
- JSValue *sp,
- OPCodeEnum op)
- {
-@@ -14458,7 +14527,7 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
- return -1;
- }
-
--static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
-+static no_inline warn_unused int js_eq_slow(JSContext *ctx, JSValue *sp,
- BOOL is_neq)
- {
- JSValue op1, op2;
-@@ -14744,7 +14813,7 @@ static no_inline int js_strict_eq_slow(JSContext *ctx, JSValue *sp,
- return 0;
- }
-
--static __exception int js_operator_in(JSContext *ctx, JSValue *sp)
-+static warn_unused int js_operator_in(JSContext *ctx, JSValue *sp)
- {
- JSValue op1, op2;
- JSAtom atom;
-@@ -14770,7 +14839,7 @@ static __exception int js_operator_in(JSContext *ctx, JSValue *sp)
- return 0;
- }
-
--static __exception int js_has_unscopable(JSContext *ctx, JSValueConst obj,
-+static warn_unused int js_has_unscopable(JSContext *ctx, JSValueConst obj,
- JSAtom atom)
- {
- JSValue arr, val;
-@@ -14788,7 +14857,7 @@ static __exception int js_has_unscopable(JSContext *ctx, JSValueConst obj,
- return ret;
- }
-
--static __exception int js_operator_instanceof(JSContext *ctx, JSValue *sp)
-+static warn_unused int js_operator_instanceof(JSContext *ctx, JSValue *sp)
- {
- JSValue op1, op2;
- BOOL ret;
-@@ -14804,7 +14873,7 @@ static __exception int js_operator_instanceof(JSContext *ctx, JSValue *sp)
- return 0;
- }
-
--static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1)
-+static warn_unused int js_operator_typeof(JSContext *ctx, JSValueConst op1)
- {
- JSAtom atom;
- uint32_t tag;
-@@ -14861,7 +14930,7 @@ static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1)
- return atom;
- }
-
--static __exception int js_operator_delete(JSContext *ctx, JSValue *sp)
-+static warn_unused int js_operator_delete(JSContext *ctx, JSValue *sp)
- {
- JSValue op1, op2;
- JSAtom atom;
-@@ -15016,7 +15085,7 @@ static JSValue js_build_mapped_arguments(JSContext *ctx, int argc,
- var_ref = get_var_ref(ctx, sf, i, TRUE);
- if (!var_ref)
- goto fail;
-- pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E | JS_PROP_VARREF);
-+ pr = add_property(ctx, p, JS_AtomFromUInt32(i), JS_PROP_C_W_E | JS_PROP_VARREF);
- if (!pr) {
- free_var_ref(ctx->rt, var_ref);
- goto fail;
-@@ -15188,7 +15257,7 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
- }
-
- /* obj -> enum_obj */
--static __exception int js_for_in_start(JSContext *ctx, JSValue *sp)
-+static warn_unused int js_for_in_start(JSContext *ctx, JSValue *sp)
- {
- sp[-1] = build_for_in_iterator(ctx, sp[-1]);
- if (JS_IsException(sp[-1]))
-@@ -15197,7 +15266,7 @@ static __exception int js_for_in_start(JSContext *ctx, JSValue *sp)
- }
-
- /* enum_obj -> enum_obj value done */
--static __exception int js_for_in_next(JSContext *ctx, JSValue *sp)
-+static warn_unused int js_for_in_next(JSContext *ctx, JSValue *sp)
- {
- JSValueConst enum_obj;
- JSObject *p;
-@@ -15218,7 +15287,7 @@ static __exception int js_for_in_next(JSContext *ctx, JSValue *sp)
- if (it->is_array) {
- if (it->idx >= it->array_length)
- goto done;
-- prop = __JS_AtomFromUInt32(it->idx);
-+ prop = JS_AtomFromUInt32(it->idx);
- it->idx++;
- } else {
- JSShape *sh = p->shape;
-@@ -15411,7 +15480,7 @@ static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj,
- }
-
- /* obj -> enum_rec (3 slots) */
--static __exception int js_for_of_start(JSContext *ctx, JSValue *sp,
-+static warn_unused int js_for_of_start(JSContext *ctx, JSValue *sp,
- BOOL is_async)
- {
- JSValue op1, obj, method;
-@@ -15432,7 +15501,7 @@ static __exception int js_for_of_start(JSContext *ctx, JSValue *sp,
- objs. If 'done' is true or in case of exception, 'enum_rec' is set
- to undefined. If 'done' is true, 'value' is always set to
- undefined. */
--static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset)
-+static warn_unused int js_for_of_next(JSContext *ctx, JSValue *sp, int offset)
- {
- JSValue value = JS_UNDEFINED;
- int done = 1;
-@@ -15478,7 +15547,7 @@ static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValueConst obj,
- return JS_EXCEPTION;
- }
-
--static __exception int js_iterator_get_value_done(JSContext *ctx, JSValue *sp)
-+static warn_unused int js_iterator_get_value_done(JSContext *ctx, JSValue *sp)
- {
- JSValue obj, value;
- BOOL done;
-@@ -15554,7 +15623,7 @@ static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,
- return FALSE;
- }
-
--static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp)
-+static warn_unused int js_append_enumerate(JSContext *ctx, JSValue *sp)
- {
- JSValue iterator, enumobj, method, value;
- int is_array_iterator;
-@@ -15634,7 +15703,7 @@ exception:
- return -1;
- }
-
--static __exception int JS_CopyDataProperties(JSContext *ctx,
-+static warn_unused int JS_CopyDataProperties(JSContext *ctx,
- JSValueConst target,
- JSValueConst source,
- JSValueConst excluded,
-@@ -16043,7 +16112,7 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
- #else
- sf->js_mode = 0;
- #endif
-- sf->cur_func = (JSValue)func_obj;
-+ sf->cur_func = func_obj;
- sf->arg_count = argc;
- arg_buf = argv;
-
-@@ -16056,7 +16125,7 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
- arg_buf[i] = JS_UNDEFINED;
- sf->arg_count = arg_count;
- }
-- sf->arg_buf = (JSValue*)arg_buf;
-+ sf->arg_buf = arg_buf;
-
- func = p->u.cfunc.c_function;
- switch(cproto) {
-@@ -16226,7 +16295,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
- #include "quickjs-opcode.h"
- [ OP_COUNT ... 255 ] = &&case_default
- };
--#define SWITCH(pc) goto *dispatch_table[opcode = *pc++];
-+#define SWITCH(pc) goto *dispatch_table[opcode = *(pc)++];
- #define CASE(op) case_ ## op
- #define DEFAULT case_default
- #define BREAK SWITCH(pc)
-@@ -16269,7 +16338,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
- return JS_ThrowTypeError(caller_ctx, "not a function");
- }
- return call_func(caller_ctx, func_obj, this_obj, argc,
-- (JSValueConst *)argv, flags);
-+ argv, flags);
- }
- b = p->u.func.function_bytecode;
-
-@@ -16287,7 +16356,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
- sf->js_mode = b->js_mode;
- arg_buf = argv;
- sf->arg_count = argc;
-- sf->cur_func = (JSValue)func_obj;
-+ sf->cur_func = func_obj;
- init_list_head(&sf->var_ref_list);
- var_refs = p->u.func.var_refs;
-
-@@ -16315,6 +16384,9 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
- rt->current_stack_frame = sf;
- ctx = b->realm; /* set the current realm */
-
-+ if (ctx->handleFunctionEntered)
-+ ctx->handleFunctionEntered(ctx, this_obj);
-+
- restart:
- for(;;) {
- int call_argc;
-@@ -16420,12 +16492,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
- int arg = *pc++;
- switch(arg) {
- case OP_SPECIAL_OBJECT_ARGUMENTS:
-- *sp++ = js_build_arguments(ctx, argc, (JSValueConst *)argv);
-+ *sp++ = js_build_arguments(ctx, argc, argv);
- if (unlikely(JS_IsException(sp[-1])))
- goto exception;
- break;
- case OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS:
-- *sp++ = js_build_mapped_arguments(ctx, argc, (JSValueConst *)argv,
-+ *sp++ = js_build_mapped_arguments(ctx, argc, argv,
- sf, min_int(argc, b->arg_count));
- if (unlikely(JS_IsException(sp[-1])))
- goto exception;
-@@ -16465,7 +16537,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
- {
- int first = get_u16(pc);
- pc += 2;
-- *sp++ = js_build_rest(ctx, first, argc, (JSValueConst *)argv);
-+ *sp++ = js_build_rest(ctx, first, argc, argv);
- if (unlikely(JS_IsException(sp[-1])))
- goto exception;
- }
-@@ -16698,7 +16770,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
- goto exception;
- call_argv = sp - call_argc;
- for(i = 0; i < call_argc; i++) {
-- ret = JS_DefinePropertyValue(ctx, ret_val, __JS_AtomFromUInt32(i), call_argv[i],
-+ ret = JS_DefinePropertyValue(ctx, ret_val, JS_AtomFromUInt32(i), call_argv[i],
- JS_PROP_C_W_E | JS_PROP_THROW);
- call_argv[i] = JS_UNDEFINED;
- if (ret < 0) {
-@@ -16717,7 +16789,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
- magic = get_u16(pc);
- pc += 2;
-
-- ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst *)&sp[-2], magic);
-+ ret_val = js_function_apply(ctx, sp[-3], 2, &sp[-2], magic);
- if (unlikely(JS_IsException(ret_val)))
- goto exception;
- JS_FreeValue(ctx, sp[-3]);
-@@ -16850,7 +16922,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
- JS_EVAL_TYPE_DIRECT, scope_idx);
- } else {
- ret_val = JS_Call(ctx, sp[-2], JS_UNDEFINED, len,
-- (JSValueConst *)tab);
-+ tab);
- }
- free_arg_list(ctx, tab, len);
- if (unlikely(JS_IsException(ret_val)))
-@@ -17474,7 +17546,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
- {
- JSValue ret;
- ret = JS_Call(ctx, sp[-3], sp[-4],
-- 1, (JSValueConst *)(sp - 1));
-+ 1, (sp - 1));
- if (JS_IsException(ret))
- goto exception;
- JS_FreeValue(ctx, sp[-1]);
-@@ -17502,7 +17574,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
- 0, NULL);
- } else {
- ret = JS_CallFree(ctx, method, sp[-4],
-- 1, (JSValueConst *)(sp - 1));
-+ 1, (sp - 1));
- }
- if (JS_IsException(ret))
- goto exception;
-@@ -17925,7 +17997,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
- sp[-2] = JS_NewInt32(ctx, r);
- sp--;
- } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
-- sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) +
-+ sp[-2] = JS_NewFloat64Impl(ctx, JS_VALUE_GET_FLOAT64(op1) +
- JS_VALUE_GET_FLOAT64(op2));
- sp--;
- } else {
-@@ -17990,7 +18062,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
- sp[-2] = JS_NewInt32(ctx, r);
- sp--;
- } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
-- sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) -
-+ sp[-2] = JS_NewFloat64Impl(ctx, JS_VALUE_GET_FLOAT64(op1) -
- JS_VALUE_GET_FLOAT64(op2));
- sp--;
- } else {
-@@ -18033,7 +18105,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
- #endif
- d = JS_VALUE_GET_FLOAT64(op1) * JS_VALUE_GET_FLOAT64(op2);
- mul_fp_res:
-- sp[-2] = __JS_NewFloat64(ctx, d);
-+ sp[-2] = JS_NewFloat64Impl(ctx, d);
- sp--;
- } else {
- goto binary_arith_slow;
-@@ -18125,7 +18197,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
- } else if (JS_TAG_IS_FLOAT64(tag)) {
- d = -JS_VALUE_GET_FLOAT64(op1);
- neg_fp_res:
-- sp[-1] = __JS_NewFloat64(ctx, d);
-+ sp[-1] = JS_NewFloat64Impl(ctx, d);
- } else {
- if (js_unary_arith_slow(ctx, sp, opcode))
- goto exception;
-@@ -18659,6 +18731,13 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
- }
- }
- exception:
-+ if (JS_IsString(rt->current_exception)) {
-+ JSValue error_obj = JS_NewError(ctx);
-+ JSAtom msgProp = JS_NewAtom(ctx, "message");
-+ JS_DefinePropertyValue(ctx, error_obj, msgProp, rt->current_exception, 0);
-+ rt->current_exception = error_obj;
-+ JS_FreeAtom(ctx, msgProp);
-+ }
- if (is_backtrace_needed(ctx, rt->current_exception)) {
- /* add the backtrace information now (it is not done
- before if the exception happens in a bytecode
-@@ -18706,6 +18785,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
- }
- }
- rt->current_stack_frame = sf->prev_frame;
-+ if (ctx->handleFunctionExited)
-+ ctx->handleFunctionExited(ctx);
- return ret_val;
- }
-
-@@ -18713,14 +18794,14 @@ JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj,
- int argc, JSValueConst *argv)
- {
- return JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,
-- argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV);
-+ argc, argv, JS_CALL_FLAG_COPY_ARGV);
- }
-
- static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj,
- int argc, JSValueConst *argv)
- {
- JSValue res = JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,
-- argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV);
-+ argc, argv, JS_CALL_FLAG_COPY_ARGV);
- JS_FreeValue(ctx, func_obj);
- return res;
- }
-@@ -18825,7 +18906,7 @@ static JSValue JS_CallConstructorInternal(JSContext *ctx,
- return JS_ThrowTypeError(ctx, "not a function");
- }
- return call_func(ctx, func_obj, new_target, argc,
-- (JSValueConst *)argv, flags);
-+ argv, flags);
- }
-
- b = p->u.func.function_bytecode;
-@@ -18854,7 +18935,7 @@ JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj,
- int argc, JSValueConst *argv)
- {
- return JS_CallConstructorInternal(ctx, func_obj, new_target,
-- argc, (JSValue *)argv,
-+ argc, argv,
- JS_CALL_FLAG_COPY_ARGV);
- }
-
-@@ -18862,7 +18943,7 @@ JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj,
- int argc, JSValueConst *argv)
- {
- return JS_CallConstructorInternal(ctx, func_obj, func_obj,
-- argc, (JSValue *)argv,
-+ argc, argv,
- JS_CALL_FLAG_COPY_ARGV);
- }
-
-@@ -18885,7 +18966,7 @@ static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
- }
-
- /* JSAsyncFunctionState (used by generator and async functions) */
--static __exception int async_func_init(JSContext *ctx, JSAsyncFunctionState *s,
-+static warn_unused int async_func_init(JSContext *ctx, JSAsyncFunctionState *s,
- JSValueConst func_obj, JSValueConst this_obj,
- int argc, JSValueConst *argv)
- {
-@@ -19227,7 +19308,7 @@ static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionData *s)
- fail:
- error = JS_GetException(ctx);
- ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED,
-- 1, (JSValueConst *)&error);
-+ 1, &error);
- JS_FreeValue(ctx, error);
- js_async_function_terminate(ctx->rt, s);
- JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
-@@ -19238,7 +19319,7 @@ static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionData *s)
- if (JS_IsUndefined(func_ret)) {
- /* function returned */
- ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED,
-- 1, (JSValueConst *)&value);
-+ 1, &value);
- JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
- JS_FreeValue(ctx, value);
- js_async_function_terminate(ctx->rt, s);
-@@ -19249,7 +19330,7 @@ static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionData *s)
- /* await */
- JS_FreeValue(ctx, func_ret); /* not used */
- promise = js_promise_resolve(ctx, ctx->promise_ctor,
-- 1, (JSValueConst *)&value, 0);
-+ 1, &value, 0);
- JS_FreeValue(ctx, value);
- if (JS_IsException(promise))
- goto fail;
-@@ -19531,7 +19612,7 @@ static int js_async_generator_completed_return(JSContext *ctx,
- int res;
-
- promise = js_promise_resolve(ctx, ctx->promise_ctor,
-- 1, (JSValueConst *)&value, 0);
-+ 1, &value, 0);
- if (JS_IsException(promise))
- return -1;
- if (js_async_generator_resolve_function_create(ctx,
-@@ -19703,7 +19784,7 @@ static JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val,
- JS_ThrowTypeError(ctx, "not an AsyncGenerator object");
- err = JS_GetException(ctx);
- res2 = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
-- 1, (JSValueConst *)&err);
-+ 1, &err);
- JS_FreeValue(ctx, err);
- JS_FreeValue(ctx, res2);
- JS_FreeValue(ctx, resolving_funcs[0]);
-@@ -20138,7 +20219,7 @@ static const JSOpCode opcode_info[OP_COUNT + (OP_TEMP_END - OP_TEMP_START)] = {
- #define short_opcode_info(op) opcode_info[op]
- #endif
-
--static __exception int next_token(JSParseState *s);
-+static warn_unused int next_token(JSParseState *s);
-
- static void free_token(JSParseState *s, JSToken *token)
- {
-@@ -20169,7 +20250,7 @@ static void free_token(JSParseState *s, JSToken *token)
- }
- }
-
--static void __attribute((unused)) dump_token(JSParseState *s,
-+static void maybe_unused dump_token(JSParseState *s,
- const JSToken *token)
- {
- switch(token->val) {
-@@ -20230,7 +20311,7 @@ static void __attribute((unused)) dump_token(JSParseState *s,
- }
- }
-
--int __attribute__((format(printf, 2, 3))) js_parse_error(JSParseState *s, const char *fmt, ...)
-+int FORMAT_ATTR(2, 3) js_parse_error(JSParseState *s, const char *fmt, ...)
- {
- JSContext *ctx = s->ctx;
- va_list ap;
-@@ -20276,7 +20357,7 @@ static int js_parse_error_reserved_identifier(JSParseState *s)
- s->token.u.ident.atom));
- }
-
--static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p)
-+static warn_unused int js_parse_template_part(JSParseState *s, const uint8_t *p)
- {
- uint32_t c;
- StringBuffer b_s, *b = &b_s;
-@@ -20337,7 +20418,7 @@ static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p)
- return -1;
- }
-
--static __exception int js_parse_string(JSParseState *s, int sep,
-+static warn_unused int js_parse_string(JSParseState *s, int sep,
- BOOL do_throw, const uint8_t *p,
- JSToken *token, const uint8_t **pp)
- {
-@@ -20482,7 +20563,7 @@ static inline BOOL token_is_pseudo_keyword(JSParseState *s, JSAtom atom) {
- !s->token.u.ident.has_escape;
- }
-
--static __exception int js_parse_regexp(JSParseState *s)
-+static warn_unused int js_parse_regexp(JSParseState *s)
- {
- const uint8_t *p;
- BOOL in_class;
-@@ -20580,8 +20661,8 @@ static __exception int js_parse_regexp(JSParseState *s)
- return -1;
- }
-
--static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize,
-- char *static_buf)
-+static warn_unused int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize,
-+ const char *static_buf)
- {
- char *buf, *new_buf;
- size_t size, new_size;
-@@ -20656,7 +20737,7 @@ static JSAtom parse_ident(JSParseState *s, const uint8_t **pp,
- }
-
-
--static __exception int next_token(JSParseState *s)
-+static warn_unused int next_token(JSParseState *s)
- {
- const uint8_t *p;
- int c;
-@@ -21204,7 +21285,7 @@ static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c)
- return atom;
- }
-
--static __exception int json_next_token(JSParseState *s)
-+static warn_unused int json_next_token(JSParseState *s)
- {
- const uint8_t *p;
- int c;
-@@ -21644,7 +21725,7 @@ static int cpool_add(JSParseState *s, JSValue val)
- return fd->cpool_count - 1;
- }
-
--static __exception int emit_push_const(JSParseState *s, JSValueConst val,
-+static warn_unused int emit_push_const(JSParseState *s, JSValueConst val,
- BOOL as_atom)
- {
- int idx;
-@@ -21654,7 +21735,7 @@ static __exception int emit_push_const(JSParseState *s, JSValueConst val,
- /* warning: JS_NewAtomStr frees the string value */
- JS_DupValue(s->ctx, val);
- atom = JS_NewAtomStr(s->ctx, JS_VALUE_GET_STRING(val));
-- if (atom != JS_ATOM_NULL && !__JS_AtomIsTaggedInt(atom)) {
-+ if (atom != JS_ATOM_NULL && !JS_AtomIsTaggedInt(atom)) {
- emit_op(s, OP_push_atom_value);
- emit_u32(s, atom);
- return 0;
-@@ -22118,14 +22199,14 @@ static int add_private_class_field(JSParseState *s, JSFunctionDef *fd,
- return idx;
- }
-
--static __exception int js_parse_expr(JSParseState *s);
--static __exception int js_parse_function_decl(JSParseState *s,
-+static warn_unused int js_parse_expr(JSParseState *s);
-+static warn_unused int js_parse_function_decl(JSParseState *s,
- JSParseFunctionEnum func_type,
- JSFunctionKindEnum func_kind,
- JSAtom func_name, const uint8_t *ptr,
- int start_line);
- static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s);
--static __exception int js_parse_function_decl2(JSParseState *s,
-+static warn_unused int js_parse_function_decl2(JSParseState *s,
- JSParseFunctionEnum func_type,
- JSFunctionKindEnum func_kind,
- JSAtom func_name,
-@@ -22133,9 +22214,9 @@ static __exception int js_parse_function_decl2(JSParseState *s,
- int function_line_num,
- JSParseExportEnum export_flag,
- JSFunctionDef **pfd);
--static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags);
--static __exception int js_parse_assign_expr(JSParseState *s);
--static __exception int js_parse_unary(JSParseState *s, int parse_flags);
-+static warn_unused int js_parse_assign_expr2(JSParseState *s, int parse_flags);
-+static warn_unused int js_parse_assign_expr(JSParseState *s);
-+static warn_unused int js_parse_unary(JSParseState *s, int parse_flags);
- static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
- JSAtom label_name,
- int label_break, int label_cont,
-@@ -22162,7 +22243,7 @@ static int seal_template_obj(JSContext *ctx, JSValueConst obj)
- return 0;
- }
-
--static __exception int js_parse_template(JSParseState *s, int call, int *argc)
-+static warn_unused int js_parse_template(JSParseState *s, int call, int *argc)
- {
- JSContext *ctx = s->ctx;
- JSValue raw_array, template_object;
-@@ -22293,7 +22374,7 @@ static BOOL token_is_ident(int tok)
- }
-
- /* if the property is an expression, name = JS_ATOM_NULL */
--static int __exception js_parse_property_name(JSParseState *s,
-+static int warn_unused js_parse_property_name(JSParseState *s,
- JSAtom *pname,
- BOOL allow_method, BOOL allow_var,
- BOOL allow_private)
-@@ -22435,7 +22516,7 @@ static int js_parse_get_pos(JSParseState *s, JSParsePos *sp)
- return 0;
- }
-
--static __exception int js_parse_seek_token(JSParseState *s, const JSParsePos *sp)
-+static warn_unused int js_parse_seek_token(JSParseState *s, const JSParsePos *sp)
- {
- s->token.line_num = sp->last_line_num;
- s->line_num = sp->line_num;
-@@ -22480,7 +22561,8 @@ static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_
- size_t level = 0;
- JSParsePos pos;
- int last_tok, tok = TOK_EOF;
-- int c, tok_len, bits = 0;
-+ int tok_len, bits = 0;
-+ char c;
-
- /* protect from underflow */
- state[level++] = 0;
-@@ -22640,7 +22722,7 @@ static void set_object_name_computed(JSParseState *s)
- }
- }
-
--static __exception int js_parse_object_literal(JSParseState *s)
-+static warn_unused int js_parse_object_literal(JSParseState *s)
- {
- JSAtom name = JS_ATOM_NULL;
- const uint8_t *start_ptr;
-@@ -22765,15 +22847,15 @@ static __exception int js_parse_object_literal(JSParseState *s)
- /* forbid the exponentiation operator in js_parse_unary() */
- #define PF_POW_FORBIDDEN (1 << 4)
-
--static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags);
-+static warn_unused int js_parse_postfix_expr(JSParseState *s, int parse_flags);
-
--static __exception int js_parse_left_hand_side_expr(JSParseState *s)
-+static warn_unused int js_parse_left_hand_side_expr(JSParseState *s)
- {
- return js_parse_postfix_expr(s, PF_POSTFIX_CALL);
- }
-
- /* XXX: could generate specific bytecode */
--static __exception int js_parse_class_default_ctor(JSParseState *s,
-+static warn_unused int js_parse_class_default_ctor(JSParseState *s,
- BOOL has_super,
- JSFunctionDef **pfd)
- {
-@@ -22864,7 +22946,7 @@ typedef struct {
- int brand_push_pos;
- } ClassFieldsDef;
-
--static __exception int emit_class_init_start(JSParseState *s,
-+static warn_unused int emit_class_init_start(JSParseState *s,
- ClassFieldsDef *cf)
- {
- int label_add_brand;
-@@ -22897,7 +22979,7 @@ static __exception int emit_class_init_start(JSParseState *s,
- return 0;
- }
-
--static __exception int add_brand(JSParseState *s, ClassFieldsDef *cf)
-+static warn_unused int add_brand(JSParseState *s, ClassFieldsDef *cf)
- {
- if (!cf->has_brand) {
- /* define the brand field in 'this' of the initializer */
-@@ -22929,7 +23011,7 @@ static void emit_class_init_end(JSParseState *s, ClassFieldsDef *cf)
- }
-
-
--static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
-+static warn_unused int js_parse_class(JSParseState *s, BOOL is_class_expr,
- JSParseExportEnum export_flag)
- {
- JSContext *ctx = s->ctx;
-@@ -23374,7 +23456,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
- return -1;
- }
-
--static __exception int js_parse_array_literal(JSParseState *s)
-+static warn_unused int js_parse_array_literal(JSParseState *s)
- {
- uint32_t idx;
- BOOL need_length;
-@@ -23410,7 +23492,7 @@ static __exception int js_parse_array_literal(JSParseState *s)
- if (js_parse_assign_expr(s))
- return -1;
- emit_op(s, OP_define_field);
-- emit_u32(s, __JS_AtomFromUInt32(idx));
-+ emit_u32(s, JS_AtomFromUInt32(idx));
- need_length = FALSE;
- }
- idx++;
-@@ -23520,7 +23602,7 @@ static BOOL has_with_scope(JSFunctionDef *s, int scope_level)
- return FALSE;
- }
-
--static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
-+static warn_unused int get_lvalue(JSParseState *s, int *popcode, int *pscope,
- JSAtom *pname, int *plabel, int *pdepth, BOOL keep,
- int tok)
- {
-@@ -23760,7 +23842,7 @@ static void put_lvalue(JSParseState *s, int opcode, int scope,
- }
- }
-
--static __exception int js_parse_expr_paren(JSParseState *s)
-+static warn_unused int js_parse_expr_paren(JSParseState *s)
- {
- if (js_parse_expect(s, '('))
- return -1;
-@@ -23778,7 +23860,7 @@ static int js_unsupported_keyword(JSParseState *s, JSAtom atom)
- JS_AtomGetStr(s->ctx, buf, sizeof(buf), atom));
- }
-
--static __exception int js_define_var(JSParseState *s, JSAtom name, int tok)
-+static warn_unused int js_define_var(JSParseState *s, JSAtom name, int tok)
- {
- JSFunctionDef *fd = s->cur_func;
- JSVarDefEnum var_def_type;
-@@ -24327,7 +24409,7 @@ static void optional_chain_test(JSParseState *s, int *poptional_chaining_label,
- }
-
- /* allowed parse_flags: PF_POSTFIX_CALL, PF_ARROW_FUNC */
--static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
-+static warn_unused int js_parse_postfix_expr(JSParseState *s, int parse_flags)
- {
- FuncCallType call_type;
- int optional_chaining_label;
-@@ -24963,17 +25045,16 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
- return 0;
- }
-
--static __exception int js_parse_delete(JSParseState *s)
-+static warn_unused int js_parse_delete(JSParseState *s)
- {
- JSFunctionDef *fd = s->cur_func;
- JSAtom name;
-- int opcode;
-
- if (next_token(s))
- return -1;
- if (js_parse_unary(s, PF_POW_FORBIDDEN))
- return -1;
-- switch(opcode = get_prev_opcode(fd)) {
-+ switch (get_prev_opcode(fd)) {
- case OP_get_field:
- {
- JSValue val;
-@@ -25024,7 +25105,7 @@ static __exception int js_parse_delete(JSParseState *s)
- }
-
- /* allowed parse_flags: PF_ARROW_FUNC, PF_POW_ALLOWED, PF_POW_FORBIDDEN */
--static __exception int js_parse_unary(JSParseState *s, int parse_flags)
-+static warn_unused int js_parse_unary(JSParseState *s, int parse_flags)
- {
- int op;
-
-@@ -25172,7 +25253,7 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags)
- }
-
- /* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
--static __exception int js_parse_expr_binary(JSParseState *s, int level,
-+static warn_unused int js_parse_expr_binary(JSParseState *s, int level,
- int parse_flags)
- {
- int op, opcode;
-@@ -25319,7 +25400,7 @@ static __exception int js_parse_expr_binary(JSParseState *s, int level,
- }
-
- /* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
--static __exception int js_parse_logical_and_or(JSParseState *s, int op,
-+static warn_unused int js_parse_logical_and_or(JSParseState *s, int op,
- int parse_flags)
- {
- int label1;
-@@ -25361,7 +25442,7 @@ static __exception int js_parse_logical_and_or(JSParseState *s, int op,
- return 0;
- }
-
--static __exception int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
-+static warn_unused int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
- {
- int label1;
-
-@@ -25389,7 +25470,7 @@ static __exception int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
- }
-
- /* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
--static __exception int js_parse_cond_expr(JSParseState *s, int parse_flags)
-+static warn_unused int js_parse_cond_expr(JSParseState *s, int parse_flags)
- {
- int label1, label2;
-
-@@ -25420,7 +25501,7 @@ static __exception int js_parse_cond_expr(JSParseState *s, int parse_flags)
- static void emit_return(JSParseState *s, BOOL hasval);
-
- /* allowed parse_flags: PF_IN_ACCEPTED */
--static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
-+static warn_unused int js_parse_assign_expr2(JSParseState *s, int parse_flags)
- {
- int opcode, op, scope;
- JSAtom name0 = JS_ATOM_NULL;
-@@ -25666,13 +25747,13 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
- return 0;
- }
-
--static __exception int js_parse_assign_expr(JSParseState *s)
-+static warn_unused int js_parse_assign_expr(JSParseState *s)
- {
- return js_parse_assign_expr2(s, PF_IN_ACCEPTED);
- }
-
- /* allowed parse_flags: PF_IN_ACCEPTED */
--static __exception int js_parse_expr2(JSParseState *s, int parse_flags)
-+static warn_unused int js_parse_expr2(JSParseState *s, int parse_flags)
- {
- BOOL comma = FALSE;
- for(;;) {
-@@ -25696,7 +25777,7 @@ static __exception int js_parse_expr2(JSParseState *s, int parse_flags)
- return 0;
- }
-
--static __exception int js_parse_expr(JSParseState *s)
-+static warn_unused int js_parse_expr(JSParseState *s)
- {
- return js_parse_expr2(s, PF_IN_ACCEPTED);
- }
-@@ -25724,7 +25805,7 @@ static void pop_break_entry(JSFunctionDef *fd)
- fd->top_break = be->prev;
- }
-
--static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont)
-+static warn_unused int emit_break(JSParseState *s, JSAtom name, int is_cont)
- {
- BlockEnv *top;
- int i, scope_level;
-@@ -25873,15 +25954,15 @@ static void emit_return(JSParseState *s, BOOL hasval)
- #define DECL_MASK_OTHER (1 << 2) /* all other declarations */
- #define DECL_MASK_ALL (DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL | DECL_MASK_OTHER)
-
--static __exception int js_parse_statement_or_decl(JSParseState *s,
-+static warn_unused int js_parse_statement_or_decl(JSParseState *s,
- int decl_mask);
-
--static __exception int js_parse_statement(JSParseState *s)
-+static warn_unused int js_parse_statement(JSParseState *s)
- {
- return js_parse_statement_or_decl(s, 0);
- }
-
--static __exception int js_parse_block(JSParseState *s)
-+static warn_unused int js_parse_block(JSParseState *s)
- {
- if (js_parse_expect(s, '{'))
- return -1;
-@@ -25901,7 +25982,7 @@ static __exception int js_parse_block(JSParseState *s)
- }
-
- /* allowed parse_flags: PF_IN_ACCEPTED */
--static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
-+static warn_unused int js_parse_var(JSParseState *s, int parse_flags, int tok,
- BOOL export_flag)
- {
- JSContext *ctx = s->ctx;
-@@ -26052,7 +26133,7 @@ static int is_let(JSParseState *s, int decl_mask)
-
- /* XXX: handle IteratorClose when exiting the loop before the
- enumeration is done */
--static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
-+static warn_unused int js_parse_for_in_of(JSParseState *s, int label_name,
- BOOL is_async)
- {
- JSContext *ctx = s->ctx;
-@@ -26283,7 +26364,7 @@ static void set_eval_ret_undefined(JSParseState *s)
- }
- }
-
--static __exception int js_parse_statement_or_decl(JSParseState *s,
-+static warn_unused int js_parse_statement_or_decl(JSParseState *s,
- int decl_mask)
- {
- JSContext *ctx = s->ctx;
-@@ -27603,7 +27684,7 @@ static int find_exported_name(GetExportNamesState *s, JSAtom name)
- return -1;
- }
-
--static __exception int get_exported_names(JSContext *ctx,
-+static warn_unused int get_exported_names(JSContext *ctx,
- GetExportNamesState *s,
- JSModuleDef *m, BOOL from_star)
- {
-@@ -27744,7 +27825,6 @@ static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)
- en->u.var_ref = res_me->u.local.var_ref;
- } else {
- JSObject *p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
-- p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
- en->u.var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
- }
- }
-@@ -28237,7 +28317,7 @@ static JSValue js_dynamic_import_job(JSContext *ctx,
- goto exception;
-
- ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED,
-- 1, (JSValueConst *)&ns);
-+ 1, &ns);
- JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
- JS_FreeValue(ctx, ns);
- JS_FreeCString(ctx, basename);
-@@ -28246,7 +28326,7 @@ static JSValue js_dynamic_import_job(JSContext *ctx,
-
- err = JS_GetException(ctx);
- ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
-- 1, (JSValueConst *)&err);
-+ 1, &err);
- JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
- JS_FreeValue(ctx, err);
- JS_FreeCString(ctx, basename);
-@@ -28343,7 +28423,7 @@ static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m)
- return ret_val;
- }
-
--static __exception JSAtom js_parse_from_clause(JSParseState *s)
-+static warn_unused JSAtom js_parse_from_clause(JSParseState *s)
- {
- JSAtom module_name;
- if (!token_is_pseudo_keyword(s, JS_ATOM_from)) {
-@@ -28366,7 +28446,7 @@ static __exception JSAtom js_parse_from_clause(JSParseState *s)
- return module_name;
- }
-
--static __exception int js_parse_export(JSParseState *s)
-+static warn_unused int js_parse_export(JSParseState *s)
- {
- JSContext *ctx = s->ctx;
- JSModuleDef *m = s->cur_func->module;
-@@ -28569,7 +28649,7 @@ static int add_import(JSParseState *s, JSModuleDef *m,
- return 0;
- }
-
--static __exception int js_parse_import(JSParseState *s)
-+static warn_unused int js_parse_import(JSParseState *s)
- {
- JSContext *ctx = s->ctx;
- JSModuleDef *m = s->cur_func->module;
-@@ -28684,7 +28764,7 @@ static __exception int js_parse_import(JSParseState *s)
- return js_parse_expect_semi(s);
- }
-
--static __exception int js_parse_source_element(JSParseState *s)
-+static warn_unused int js_parse_source_element(JSParseState *s)
- {
- JSFunctionDef *fd = s->cur_func;
- int tok;
-@@ -29608,8 +29688,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
- }
- var_idx = idx;
- break;
-- } else
-- if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
-+ } else if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
- dbuf_putc(bc, OP_get_loc);
- dbuf_put_u16(bc, idx);
- var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
-@@ -30359,7 +30438,7 @@ static void set_closure_from_var(JSContext *ctx, JSClosureVar *cv,
-
- /* for direct eval compilation: add references to the variables of the
- calling function */
--static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
-+static warn_unused int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
- JSFunctionBytecode *b, int scope_idx)
- {
- int i, count;
-@@ -30779,7 +30858,7 @@ static int get_label_pos(JSFunctionDef *s, int label)
-
- /* convert global variable accesses to local variables or closure
- variables when necessary */
--static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
-+static warn_unused int resolve_variables(JSContext *ctx, JSFunctionDef *s)
- {
- int pos, pos_next, bc_len, op, len, i, idx, line_num;
- uint8_t *bc_buf;
-@@ -31343,7 +31422,7 @@ static void put_short_code(DynBuf *bc_out, int op, int idx)
- }
-
- /* peephole optimizations and resolve goto/labels */
--static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
-+static warn_unused int resolve_labels(JSContext *ctx, JSFunctionDef *s)
- {
- int pos, pos_next, bc_len, op, op1, len, i, line_num;
- const uint8_t *bc_buf;
-@@ -32152,8 +32231,7 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
- bc_out.buf[pos - 1] = jp->op = OP_if_false8 + (op - OP_if_false);
- }
- goto shrink;
-- } else
-- if (diff == (int16_t)diff && op == OP_goto) {
-+ } else if (diff == (int16_t)diff && op == OP_goto) {
- //put_u16(bc_out.buf + pos, diff);
- jp->size = 2;
- delta = 2;
-@@ -32236,7 +32314,7 @@ typedef struct StackSizeState {
- } StackSizeState;
-
- /* 'op' is only used for error indication */
--static __exception int ss_check(JSContext *ctx, StackSizeState *s,
-+static warn_unused int ss_check(JSContext *ctx, StackSizeState *s,
- int pos, int op, int stack_len)
- {
- if ((unsigned)pos >= s->bc_len) {
-@@ -32272,7 +32350,7 @@ static __exception int ss_check(JSContext *ctx, StackSizeState *s,
- return 0;
- }
-
--static __exception int compute_stack_size(JSContext *ctx,
-+static warn_unused int compute_stack_size(JSContext *ctx,
- JSFunctionDef *fd,
- int *pstack_size)
- {
-@@ -32593,7 +32671,9 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
- }
- } else {
- b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
-+ if (fd->arg_count)
- memcpy(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0]));
-+ if (fd->var_count)
- memcpy(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0]));
- }
- b->var_count = fd->var_count;
-@@ -32721,7 +32801,7 @@ static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b)
- }
- }
-
--static __exception int js_parse_directives(JSParseState *s)
-+static warn_unused int js_parse_directives(JSParseState *s)
- {
- char str[20];
- JSParsePos pos;
-@@ -32895,7 +32975,7 @@ static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s)
-
- /* func_name must be JS_ATOM_NULL for JS_PARSE_FUNC_STATEMENT and
- JS_PARSE_FUNC_EXPR, JS_PARSE_FUNC_ARROW and JS_PARSE_FUNC_VAR */
--static __exception int js_parse_function_decl2(JSParseState *s,
-+static warn_unused int js_parse_function_decl2(JSParseState *s,
- JSParseFunctionEnum func_type,
- JSFunctionKindEnum func_kind,
- JSAtom func_name,
-@@ -33443,7 +33523,7 @@ done:
- return -1;
- }
-
--static __exception int js_parse_function_decl(JSParseState *s,
-+static warn_unused int js_parse_function_decl(JSParseState *s,
- JSParseFunctionEnum func_type,
- JSFunctionKindEnum func_kind,
- JSAtom func_name,
-@@ -33455,7 +33535,7 @@ static __exception int js_parse_function_decl(JSParseState *s,
- NULL);
- }
-
--static __exception int js_parse_program(JSParseState *s)
-+static warn_unused int js_parse_program(JSParseState *s)
- {
- JSFunctionDef *fd = s->cur_func;
- int idx;
-@@ -33497,12 +33577,12 @@ static __exception int js_parse_program(JSParseState *s)
-
- static void js_parse_init(JSContext *ctx, JSParseState *s,
- const char *input, size_t input_len,
-- const char *filename)
-+ const char *filename, int line)
- {
- memset(s, 0, sizeof(*s));
- s->ctx = ctx;
- s->filename = filename;
-- s->line_num = 1;
-+ s->line_num = line;
- s->buf_ptr = (const uint8_t *)input;
- s->buf_end = s->buf_ptr + input_len;
- s->token.val = ' ';
-@@ -33573,9 +33653,9 @@ static void skip_shebang(JSParseState *s)
- }
-
- /* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
--static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
-+static JSValue JS_EvalInternalImpl(JSContext *ctx, JSValueConst this_obj,
- const char *input, size_t input_len,
-- const char *filename, int flags, int scope_idx)
-+ const char *filename, int line, int flags, int scope_idx)
- {
- JSParseState s1, *s = &s1;
- int err, js_mode, eval_type;
-@@ -33586,7 +33666,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
- JSFunctionDef *fd;
- JSModuleDef *m;
-
-- js_parse_init(ctx, s, input, input_len, filename);
-+ js_parse_init(ctx, s, input, input_len, filename, line);
- skip_shebang(s);
-
- eval_type = flags & JS_EVAL_TYPE_MASK;
-@@ -33620,7 +33700,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
- js_mode |= JS_MODE_STRICT;
- }
- }
-- fd = js_new_function_def(ctx, NULL, TRUE, FALSE, filename, 1);
-+ fd = js_new_function_def(ctx, NULL, TRUE, FALSE, filename, line);
- if (!fd)
- goto fail1;
- s->cur_func = fd;
-@@ -33686,12 +33766,12 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
- /* the indirection is needed to make 'eval' optional */
- static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
- const char *input, size_t input_len,
-- const char *filename, int flags, int scope_idx)
-+ const char *filename, int line, int flags, int scope_idx)
- {
- if (unlikely(!ctx->eval_internal)) {
- return JS_ThrowTypeError(ctx, "eval is not supported");
- }
-- return ctx->eval_internal(ctx, this_obj, input, input_len, filename,
-+ return ctx->eval_internal(ctx, this_obj, input, input_len, filename, line,
- flags, scope_idx);
- }
-
-@@ -33707,7 +33787,7 @@ static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
- str = JS_ToCStringLen(ctx, &len, val);
- if (!str)
- return JS_EXCEPTION;
-- ret = JS_EvalInternal(ctx, this_obj, str, len, "<input>", flags, scope_idx);
-+ ret = JS_EvalInternal(ctx, this_obj, str, len, "<input>", 1, flags, scope_idx);
- JS_FreeCString(ctx, str);
- return ret;
-
-@@ -33715,14 +33795,14 @@ static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
-
- JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,
- const char *input, size_t input_len,
-- const char *filename, int eval_flags)
-+ const char *filename, int line, int eval_flags)
- {
- int eval_type = eval_flags & JS_EVAL_TYPE_MASK;
- JSValue ret;
-
- assert(eval_type == JS_EVAL_TYPE_GLOBAL ||
- eval_type == JS_EVAL_TYPE_MODULE);
-- ret = JS_EvalInternal(ctx, this_obj, input, input_len, filename,
-+ ret = JS_EvalInternal(ctx, this_obj, input, input_len, filename, line,
- eval_flags, -1);
- return ret;
- }
-@@ -33730,7 +33810,7 @@ JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,
- JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
- const char *filename, int eval_flags)
- {
-- return JS_EvalThis(ctx, ctx->global_obj, input, input_len, filename,
-+ return JS_EvalThis(ctx, ctx->global_obj, input, input_len, filename, 1,
- eval_flags);
- }
-
-@@ -33948,7 +34028,7 @@ static void bc_put_u16(BCWriterState *s, uint16_t v)
- dbuf_put_u16(&s->dbuf, v);
- }
-
--static __maybe_unused void bc_put_u32(BCWriterState *s, uint32_t v)
-+static maybe_unused void bc_put_u32(BCWriterState *s, uint32_t v)
- {
- if (s->byte_swap)
- v = bswap32(v);
-@@ -33982,7 +34062,7 @@ static int bc_atom_to_idx(BCWriterState *s, uint32_t *pres, JSAtom atom)
- {
- uint32_t v;
-
-- if (atom < s->first_atom || __JS_AtomIsTaggedInt(atom)) {
-+ if (atom < s->first_atom || JS_AtomIsTaggedInt(atom)) {
- *pres = atom;
- return 0;
- }
-@@ -34022,8 +34102,8 @@ static int bc_put_atom(BCWriterState *s, JSAtom atom)
- {
- uint32_t v;
-
-- if (__JS_AtomIsTaggedInt(atom)) {
-- v = (__JS_AtomToUInt32(atom) << 1) | 1;
-+ if (JS_AtomIsTaggedInt(atom)) {
-+ v = (JS_AtomToUInt32(atom) << 1) | 1;
- } else {
- if (bc_atom_to_idx(s, &v, atom))
- return -1;
-@@ -34142,7 +34222,7 @@ static int JS_WriteFunctionBytecode(BCWriterState *s,
- static void JS_WriteString(BCWriterState *s, JSString *p)
- {
- int i;
-- bc_put_leb128(s, ((uint32_t)p->len << 1) | p->is_wide_char);
-+ bc_put_leb128(s, (p->len << 1) | p->is_wide_char);
- if (p->is_wide_char) {
- for(i = 0; i < p->len; i++)
- bc_put_u16(s, p->u.str16[i]);
-@@ -34800,7 +34880,7 @@ typedef struct BCReaderState {
- } BCReaderState;
-
- #ifdef DUMP_READ_OBJECT
--static void __attribute__((format(printf, 2, 3))) bc_read_trace(BCReaderState *s, const char *fmt, ...) {
-+static void FORMAT_ATTR(2, 3) bc_read_trace(BCReaderState *s, const char *fmt, ...) {
- va_list ap;
- int i, n, n0;
-
-@@ -34863,7 +34943,7 @@ static int bc_get_u16(BCReaderState *s, uint16_t *pval)
- return 0;
- }
-
--static __maybe_unused int bc_get_u32(BCReaderState *s, uint32_t *pval)
-+static maybe_unused int bc_get_u32(BCReaderState *s, uint32_t *pval)
- {
- if (unlikely(s->buf_end - s->ptr < 4)) {
- *pval = 0; /* avoid warning */
-@@ -34937,7 +35017,7 @@ static int bc_idx_to_atom(BCReaderState *s, JSAtom *patom, uint32_t idx)
- {
- JSAtom atom;
-
-- if (__JS_AtomIsTaggedInt(idx)) {
-+ if (JS_AtomIsTaggedInt(idx)) {
- atom = idx;
- } else if (idx < s->first_atom) {
- atom = JS_DupAtom(s->ctx, idx);
-@@ -34961,7 +35041,7 @@ static int bc_get_atom(BCReaderState *s, JSAtom *patom)
- if (bc_get_leb128(s, &v))
- return -1;
- if (v & 1) {
-- *patom = __JS_AtomFromUInt32(v >> 1);
-+ *patom = JS_AtomFromUInt32(v >> 1);
- return 0;
- } else {
- return bc_idx_to_atom(s, patom, v >> 1);
-@@ -35776,7 +35856,7 @@ static JSValue JS_ReadObjectRec(BCReaderState *s)
- if (bc_get_u64(s, &u.u64))
- return JS_EXCEPTION;
- bc_read_trace(s, "%g\n", u.d);
-- obj = __JS_NewFloat64(ctx, u.d);
-+ obj = JS_NewFloat64Impl(ctx, u.d);
- }
- break;
- case BC_TAG_STRING:
-@@ -36084,7 +36164,7 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj,
- val = JS_NewInt64(ctx, e->u.i64);
- break;
- case JS_DEF_PROP_DOUBLE:
-- val = __JS_NewFloat64(ctx, e->u.f64);
-+ val = JS_NewFloat64Impl(ctx, e->u.f64);
- break;
- case JS_DEF_PROP_UNDEFINED:
- val = JS_UNDEFINED;
-@@ -36148,7 +36228,7 @@ int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
- val = JS_NewInt64(ctx, e->u.i64);
- break;
- case JS_DEF_PROP_DOUBLE:
-- val = __JS_NewFloat64(ctx, e->u.f64);
-+ val = JS_NewFloat64Impl(ctx, e->u.f64);
- break;
- case JS_DEF_OBJECT:
- val = JS_NewObject(ctx);
-@@ -36381,7 +36461,7 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
- return -1;
- }
-
--static __exception int JS_DefinePropertyDesc(JSContext *ctx, JSValueConst obj,
-+static warn_unused int JS_DefinePropertyDesc(JSContext *ctx, JSValueConst obj,
- JSAtom prop, JSValueConst desc,
- int flags)
- {
-@@ -36397,7 +36477,7 @@ static __exception int JS_DefinePropertyDesc(JSContext *ctx, JSValueConst obj,
- return ret;
- }
-
--static __exception int JS_ObjectDefineProperties(JSContext *ctx,
-+static warn_unused int JS_ObjectDefineProperties(JSContext *ctx,
- JSValueConst obj,
- JSValueConst properties)
- {
-@@ -36882,32 +36962,6 @@ static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val,
- return JS_NewBool(ctx, ret);
- }
-
--static JSValue js_object_hasOwn(JSContext *ctx, JSValueConst this_val,
-- int argc, JSValueConst *argv)
--{
-- JSValue obj;
-- JSAtom atom;
-- JSObject *p;
-- BOOL ret;
--
-- obj = JS_ToObject(ctx, argv[0]);
-- if (JS_IsException(obj))
-- return obj;
-- atom = JS_ValueToAtom(ctx, argv[1]);
-- if (unlikely(atom == JS_ATOM_NULL)) {
-- JS_FreeValue(ctx, obj);
-- return JS_EXCEPTION;
-- }
-- p = JS_VALUE_GET_OBJ(obj);
-- ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
-- JS_FreeAtom(ctx, atom);
-- JS_FreeValue(ctx, obj);
-- if (ret < 0)
-- return JS_EXCEPTION;
-- else
-- return JS_NewBool(ctx, ret);
--}
--
- static JSValue js_object_valueOf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
-@@ -37447,6 +37501,32 @@ exception:
- return res;
- }
-
-+static JSValue js_object_hasOwn(JSContext *ctx, JSValueConst this_val,
-+ int argc, JSValueConst *argv)
-+{
-+ JSValue obj;
-+ JSAtom atom;
-+ JSObject *p;
-+ BOOL ret;
-+
-+ obj = JS_ToObject(ctx, argv[0]);
-+ if (JS_IsException(obj))
-+ return obj;
-+ atom = JS_ValueToAtom(ctx, argv[1]);
-+ if (unlikely(atom == JS_ATOM_NULL)) {
-+ JS_FreeValue(ctx, obj);
-+ return JS_EXCEPTION;
-+ }
-+ p = JS_VALUE_GET_OBJ(obj);
-+ ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
-+ JS_FreeAtom(ctx, atom);
-+ JS_FreeValue(ctx, obj);
-+ if (ret < 0)
-+ return JS_EXCEPTION;
-+ else
-+ return JS_NewBool(ctx, ret);
-+}
-+
- static const JSCFunctionListEntry js_object_funcs[] = {
- JS_CFUNC_DEF("create", 2, js_object_create ),
- JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 0 ),
-@@ -37576,7 +37656,7 @@ static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target,
- return JS_EXCEPTION;
- }
-
--static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
-+static warn_unused int js_get_length32(JSContext *ctx, uint32_t *pres,
- JSValueConst obj)
- {
- JSValue len_val;
-@@ -37588,7 +37668,7 @@ static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
- return JS_ToUint32Free(ctx, pres, len_val);
- }
-
--static __exception int js_get_length64(JSContext *ctx, int64_t *pres,
-+static warn_unused int js_get_length64(JSContext *ctx, int64_t *pres,
- JSValueConst obj)
- {
- JSValue len_val;
-@@ -37673,9 +37753,9 @@ static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
- if (!tab)
- return JS_EXCEPTION;
- if (magic & 1) {
-- ret = JS_CallConstructor2(ctx, this_val, this_arg, len, (JSValueConst *)tab);
-+ ret = JS_CallConstructor2(ctx, this_val, this_arg, len, tab);
- } else {
-- ret = JS_Call(ctx, this_val, this_arg, len, (JSValueConst *)tab);
-+ ret = JS_Call(ctx, this_val, this_arg, len, tab);
- }
- free_arg_list(ctx, tab, len);
- return ret;
-@@ -38889,8 +38969,7 @@ static JSValue js_array_toString(JSContext *ctx, JSValueConst this_val,
- method = JS_GetProperty(ctx, obj, JS_ATOM_join);
- if (JS_IsException(method)) {
- ret = JS_EXCEPTION;
-- } else
-- if (!JS_IsFunction(ctx, method)) {
-+ } else if (!JS_IsFunction(ctx, method)) {
- /* Use intrinsic Object.prototype.toString */
- JS_FreeValue(ctx, method);
- ret = js_object_toString(ctx, obj, 0, NULL);
-@@ -39138,8 +39217,7 @@ static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val,
- if (argc == 0) {
- item_count = 0;
- del_count = 0;
-- } else
-- if (argc == 1) {
-+ } else if (argc == 1) {
- item_count = 0;
- del_count = len - start;
- } else {
-@@ -39283,8 +39361,8 @@ static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target,
- if (!JS_IsUndefined(mapperFunction)) {
- JSValueConst args[3] = { element, JS_NewInt64(ctx, sourceIndex), source };
- element = JS_Call(ctx, mapperFunction, thisArg, 3, args);
-- JS_FreeValue(ctx, (JSValue)args[0]);
-- JS_FreeValue(ctx, (JSValue)args[1]);
-+ JS_FreeValue(ctx, args[0]);
-+ JS_FreeValue(ctx, args[1]);
- if (JS_IsException(element))
- return -1;
- }
-@@ -39915,7 +39993,7 @@ static JSValue js_number_toFixed(JSContext *ctx, JSValueConst this_val,
- if (f < 0 || f > 100)
- return JS_ThrowRangeError(ctx, "invalid number of digits");
- if (fabs(d) >= 1e21) {
-- return JS_ToStringFree(ctx, __JS_NewFloat64(ctx, d));
-+ return JS_ToStringFree(ctx, JS_NewFloat64Impl(ctx, d));
- } else {
- return js_dtoa(ctx, d, 10, f, JS_DTOA_FRAC_FORMAT);
- }
-@@ -39936,7 +40014,7 @@ static JSValue js_number_toExponential(JSContext *ctx, JSValueConst this_val,
- if (JS_ToInt32Sat(ctx, &f, argv[0]))
- return JS_EXCEPTION;
- if (!isfinite(d)) {
-- return JS_ToStringFree(ctx, __JS_NewFloat64(ctx, d));
-+ return JS_ToStringFree(ctx, JS_NewFloat64Impl(ctx, d));
- }
- if (JS_IsUndefined(argv[0])) {
- flags = 0;
-@@ -39968,7 +40046,7 @@ static JSValue js_number_toPrecision(JSContext *ctx, JSValueConst this_val,
- return JS_EXCEPTION;
- if (!isfinite(d)) {
- to_string:
-- return JS_ToStringFree(ctx, __JS_NewFloat64(ctx, d));
-+ return JS_ToStringFree(ctx, JS_NewFloat64Impl(ctx, d));
- }
- if (p < 1 || p > 100)
- return JS_ThrowRangeError(ctx, "invalid number of digits");
-@@ -40089,11 +40167,11 @@ static int js_string_get_own_property(JSContext *ctx,
- uint32_t idx, ch;
-
- /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
-- if (__JS_AtomIsTaggedInt(prop)) {
-+ if (JS_AtomIsTaggedInt(prop)) {
- p = JS_VALUE_GET_OBJ(obj);
- if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
- p1 = JS_VALUE_GET_STRING(p->u.object_data);
-- idx = __JS_AtomToUInt32(prop);
-+ idx = JS_AtomToUInt32(prop);
- if (idx < p1->len) {
- if (desc) {
- if (p1->is_wide_char)
-@@ -40122,8 +40200,8 @@ static int js_string_define_own_property(JSContext *ctx,
- JSObject *p;
- JSString *p1, *p2;
-
-- if (__JS_AtomIsTaggedInt(prop)) {
-- idx = __JS_AtomToUInt32(prop);
-+ if (JS_AtomIsTaggedInt(prop)) {
-+ idx = JS_AtomToUInt32(prop);
- p = JS_VALUE_GET_OBJ(this_obj);
- if (JS_VALUE_GET_TAG(p->u.object_data) != JS_TAG_STRING)
- goto def;
-@@ -40157,8 +40235,8 @@ static int js_string_delete_property(JSContext *ctx,
- {
- uint32_t idx;
-
-- if (__JS_AtomIsTaggedInt(prop)) {
-- idx = __JS_AtomToUInt32(prop);
-+ if (JS_AtomIsTaggedInt(prop)) {
-+ idx = JS_AtomToUInt32(prop);
- if (idx < js_string_obj_get_length(ctx, obj)) {
- return FALSE;
- }
-@@ -40701,7 +40779,7 @@ static JSValue js_string_match(JSContext *ctx, JSValueConst this_val,
- str = JS_NewString(ctx, "g");
- if (JS_IsException(str))
- goto fail;
-- args[args_len++] = (JSValueConst)str;
-+ args[args_len++] = str;
- }
- rx = JS_CallConstructor(ctx, ctx->regexp_ctor, args_len, args);
- JS_FreeValue(ctx, str);
-@@ -40710,7 +40788,7 @@ static JSValue js_string_match(JSContext *ctx, JSValueConst this_val,
- JS_FreeValue(ctx, S);
- return JS_EXCEPTION;
- }
-- result = JS_InvokeFree(ctx, rx, atom, 1, (JSValueConst *)&S);
-+ result = JS_InvokeFree(ctx, rx, atom, 1, &S);
- JS_FreeValue(ctx, S);
- return result;
- }
-@@ -41759,7 +41837,7 @@ static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
- uint32_t tag;
-
- if (unlikely(argc == 0)) {
-- return __JS_NewFloat64(ctx, is_max ? -1.0 / 0.0 : 1.0 / 0.0);
-+ return JS_NewFloat64Impl(ctx, is_max ? INFINITY : -INFINITY);
- }
-
- tag = JS_VALUE_GET_TAG(argv[0]);
-@@ -41911,9 +41989,13 @@ static uint64_t xorshift64star(uint64_t *pstate)
-
- static void js_random_init(JSContext *ctx)
- {
-+#ifdef _MSC_VER
-+ ctx->random_state = time(NULL);
-+#else
- struct timeval tv;
- gettimeofday(&tv, NULL);
- ctx->random_state = ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec;
-+#endif
- /* the state must be non zero */
- if (ctx->random_state == 0)
- ctx->random_state = 1;
-@@ -41928,15 +42010,21 @@ static JSValue js_math_random(JSContext *ctx, JSValueConst this_val,
- v = xorshift64star(&ctx->random_state);
- /* 1.0 <= u.d < 2 */
- u.u64 = ((uint64_t)0x3ff << 52) | (v >> 12);
-- return __JS_NewFloat64(ctx, u.d - 1.0);
-+ return JS_NewFloat64Impl(ctx, u.d - 1.0);
- }
-
-+// MSVC inexplicably refuses to initialize the array below with
-+// these functions, so use wrappers.
-+static double floorWrapper(double x) { return floor(x); }
-+static double ceilWrapper(double x) { return ceil(x); }
-+static double log2Wrapper(double x) { return log2(x); }
-+
- static const JSCFunctionListEntry js_math_funcs[] = {
- JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0 ),
- JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1 ),
- JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, fabs ),
-- JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, floor ),
-- JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, ceil ),
-+ JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, floorWrapper ),
-+ JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, ceilWrapper ),
- JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round ),
- JS_CFUNC_SPECIAL_DEF("sqrt", 1, f_f, sqrt ),
-
-@@ -41961,7 +42049,7 @@ static const JSCFunctionListEntry js_math_funcs[] = {
- JS_CFUNC_SPECIAL_DEF("atanh", 1, f_f, atanh ),
- JS_CFUNC_SPECIAL_DEF("expm1", 1, f_f, expm1 ),
- JS_CFUNC_SPECIAL_DEF("log1p", 1, f_f, log1p ),
-- JS_CFUNC_SPECIAL_DEF("log2", 1, f_f, log2 ),
-+ JS_CFUNC_SPECIAL_DEF("log2", 1, f_f, log2Wrapper ),
- JS_CFUNC_SPECIAL_DEF("log10", 1, f_f, log10 ),
- JS_CFUNC_SPECIAL_DEF("cbrt", 1, f_f, cbrt ),
- JS_CFUNC_DEF("hypot", 2, js_math_hypot ),
-@@ -42004,9 +42092,16 @@ static JSValue js___date_clock(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
- {
- int64_t d;
-+#ifdef _MSC_VER
-+ SYSTEMTIME st;
-+ GetSystemTime(&st);
-+ SystemTimeToFileTime(&st, (FILETIME *) &d);
-+ d /= 10;
-+#else
- struct timeval tv;
- gettimeofday(&tv, NULL);
- d = (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
-+#endif
- return JS_NewInt64(ctx, d);
- }
-
-@@ -43686,7 +43781,7 @@ JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
- JSParseState s1, *s = &s1;
- JSValue val = JS_UNDEFINED;
-
-- js_parse_init(ctx, s, buf, buf_len, filename);
-+ js_parse_init(ctx, s, buf, buf_len, filename, 1);
- s->ext_json = ((flags & JS_PARSE_JSON_EXT) != 0);
- if (json_next_token(s))
- goto fail;
-@@ -43937,7 +44032,7 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
- goto exception;
- }
- #endif
-- v = js_array_includes(ctx, jsc->stack, 1, (JSValueConst *)&val);
-+ v = js_array_includes(ctx, jsc->stack, 1, &val);
- if (JS_IsException(v))
- goto exception;
- if (JS_ToBoolFree(ctx, v)) {
-@@ -43958,7 +44053,7 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
- sep = JS_DupValue(ctx, jsc->empty);
- sep1 = JS_DupValue(ctx, jsc->empty);
- }
-- v = js_array_push(ctx, jsc->stack, 1, (JSValueConst *)&val, 0);
-+ v = js_array_push(ctx, jsc->stack, 1, &val, 0);
- if (check_exception_free(ctx, v))
- goto exception;
- ret = JS_IsArray(ctx, val);
-@@ -43998,7 +44093,7 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
- if (!JS_IsUndefined(jsc->property_list))
- tab = JS_DupValue(ctx, jsc->property_list);
- else
-- tab = js_object_keys(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val, JS_ITERATOR_KIND_KEY);
-+ tab = js_object_keys(ctx, JS_UNDEFINED, 1, &val, JS_ITERATOR_KIND_KEY);
- if (JS_IsException(tab))
- goto exception;
- if (js_get_length64(ctx, &len, tab))
-@@ -44146,7 +44241,7 @@ JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
- continue;
- }
- present = js_array_includes(ctx, jsc->property_list,
-- 1, (JSValueConst *)&v);
-+ 1, &v);
- if (JS_IsException(present)) {
- JS_FreeValue(ctx, v);
- goto exception;
-@@ -44270,7 +44365,7 @@ static JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val,
- tab = build_arg_list(ctx, &len, array_arg);
- if (!tab)
- return JS_EXCEPTION;
-- ret = JS_CallConstructor2(ctx, func, new_target, len, (JSValueConst *)tab);
-+ ret = JS_CallConstructor2(ctx, func, new_target, len, tab);
- free_arg_list(ctx, tab, len);
- return ret;
- }
-@@ -44475,7 +44570,7 @@ static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj)
- return JS_EXCEPTION;
- if (JS_IsUndefined(method))
- return JS_GetPrototype(ctx, s->target);
-- ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
-+ ret = JS_CallFree(ctx, method, s->handler, 1, &s->target);
- if (JS_IsException(ret))
- return ret;
- if (JS_VALUE_GET_TAG(ret) != JS_TAG_NULL &&
-@@ -44562,7 +44657,7 @@ static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj)
- return -1;
- if (JS_IsUndefined(method))
- return JS_IsExtensible(ctx, s->target);
-- ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
-+ ret = JS_CallFree(ctx, method, s->handler, 1, &s->target);
- if (JS_IsException(ret))
- return -1;
- res = JS_ToBoolFree(ctx, ret);
-@@ -44588,7 +44683,7 @@ static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj)
- return -1;
- if (JS_IsUndefined(method))
- return JS_PreventExtensions(ctx, s->target);
-- ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
-+ ret = JS_CallFree(ctx, method, s->handler, 1, &s->target);
- if (JS_IsException(ret))
- return -1;
- res = JS_ToBoolFree(ctx, ret);
-@@ -45072,7 +45167,7 @@ static int js_proxy_get_own_property_names(JSContext *ctx,
- JS_VALUE_GET_OBJ(s->target),
- JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK);
- }
-- prop_array = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
-+ prop_array = JS_CallFree(ctx, method, s->handler, 1, &s->target);
- if (JS_IsException(prop_array))
- return -1;
- tab = NULL;
-@@ -45408,7 +45503,7 @@ static JSValue js_symbol_toString(JSContext *ctx, JSValueConst this_val,
- if (JS_IsException(val))
- return val;
- /* XXX: use JS_ToStringInternal() with a flags */
-- ret = js_string_constructor(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val);
-+ ret = js_string_constructor(ctx, JS_UNDEFINED, 1, &val);
- JS_FreeValue(ctx, val);
- return ret;
- }
-@@ -45558,7 +45653,7 @@ static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target,
- break;
- }
- if (is_set) {
-- ret = JS_Call(ctx, adder, obj, 1, (JSValueConst *)&item);
-+ ret = JS_Call(ctx, adder, obj, 1, &item);
- if (JS_IsException(ret)) {
- JS_FreeValue(ctx, item);
- goto fail;
-@@ -45729,7 +45824,7 @@ static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s,
- } else {
- JS_DupValue(ctx, key);
- }
-- mr->key = (JSValue)key;
-+ mr->key = key;
- h = map_hash_key(ctx, key) & (s->hash_size - 1);
- list_add_tail(&mr->hash_link, &s->hash_table[h]);
- list_add_tail(&mr->link, &s->records);
-@@ -45951,7 +46046,7 @@ static JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val,
- args[0] = args[1];
- else
- args[0] = JS_DupValue(ctx, mr->value);
-- args[2] = (JSValue)this_val;
-+ args[2] = this_val;
- ret = JS_Call(ctx, func, this_arg, 3, (JSValueConst *)args);
- JS_FreeValue(ctx, args[0]);
- if (!magic)
-@@ -46343,7 +46438,7 @@ static JSValue promise_reaction_job(JSContext *ctx, int argc,
- functions */
- if (!JS_IsUndefined(func)) {
- res2 = JS_Call(ctx, func, JS_UNDEFINED,
-- 1, (JSValueConst *)&res);
-+ 1, &res);
- } else {
- res2 = JS_UNDEFINED;
- }
-@@ -46426,7 +46521,7 @@ static JSValue js_promise_resolve_thenable_job(JSContext *ctx,
- res = JS_Call(ctx, then, thenable, 2, (JSValueConst *)args);
- if (JS_IsException(res)) {
- JSValue error = JS_GetException(ctx);
-- res = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);
-+ res = JS_Call(ctx, args[1], JS_UNDEFINED, 1, &error);
- JS_FreeValue(ctx, error);
- }
- JS_FreeValue(ctx, args[0]);
-@@ -46626,7 +46721,7 @@ static JSValue js_promise_constructor(JSContext *ctx, JSValueConst new_target,
- if (JS_IsException(ret)) {
- JSValue ret2, error;
- error = JS_GetException(ctx);
-- ret2 = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);
-+ ret2 = JS_Call(ctx, args[1], JS_UNDEFINED, 1, &error);
- JS_FreeValue(ctx, error);
- if (JS_IsException(ret2))
- goto fail1;
-@@ -46683,10 +46778,10 @@ static JSValue js_new_promise_capability(JSContext *ctx,
-
- if (JS_IsUndefined(ctor)) {
- result_promise = js_promise_constructor(ctx, ctor, 1,
-- (JSValueConst *)&executor);
-+ &executor);
- } else {
- result_promise = JS_CallConstructor(ctx, ctor, 1,
-- (JSValueConst *)&executor);
-+ &executor);
- }
- if (JS_IsException(result_promise))
- goto fail;
-@@ -46770,7 +46865,7 @@ static JSValue js_promise___newPromiseCapability(JSContext *ctx,
- }
- #endif
-
--static __exception int remainingElementsCount_add(JSContext *ctx,
-+static warn_unused int remainingElementsCount_add(JSContext *ctx,
- JSValueConst resolve_element_env,
- int addend)
- {
-@@ -46851,10 +46946,10 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx,
- error = js_aggregate_error_constructor(ctx, values);
- if (JS_IsException(error))
- return JS_EXCEPTION;
-- ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&error);
-+ ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, &error);
- JS_FreeValue(ctx, error);
- } else {
-- ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&values);
-+ ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, &values);
- }
- if (JS_IsException(ret))
- return ret;
-@@ -46890,7 +46985,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
- fail_reject:
- error = JS_GetException(ctx);
- ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
-- (JSValueConst *)&error);
-+ &error);
- JS_FreeValue(ctx, error);
- if (JS_IsException(ret))
- goto fail;
-@@ -46921,7 +47016,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
- if (done)
- break;
- next_promise = JS_Call(ctx, promise_resolve,
-- this_val, 1, (JSValueConst *)&item);
-+ this_val, 1, &item);
- JS_FreeValue(ctx, item);
- if (JS_IsException(next_promise)) {
- fail_reject1:
-@@ -46929,7 +47024,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
- goto fail_reject;
- }
- resolve_element_data[0] = JS_NewBool(ctx, FALSE);
-- resolve_element_data[1] = (JSValueConst)JS_NewInt32(ctx, index);
-+ resolve_element_data[1] = JS_NewInt32(ctx, index);
- resolve_element_data[2] = values;
- resolve_element_data[3] = resolving_funcs[is_promise_any];
- resolve_element_data[4] = resolve_element_env;
-@@ -46989,7 +47084,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
- values = error;
- }
- ret = JS_Call(ctx, resolving_funcs[is_promise_any], JS_UNDEFINED,
-- 1, (JSValueConst *)&values);
-+ 1, &values);
- if (check_exception_free(ctx, ret))
- goto fail_reject;
- }
-@@ -47032,7 +47127,7 @@ static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val,
- fail_reject:
- error = JS_GetException(ctx);
- ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
-- (JSValueConst *)&error);
-+ &error);
- JS_FreeValue(ctx, error);
- if (JS_IsException(ret))
- goto fail;
-@@ -47051,7 +47146,7 @@ static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val,
- if (done)
- break;
- next_promise = JS_Call(ctx, promise_resolve,
-- this_val, 1, (JSValueConst *)&item);
-+ this_val, 1, &item);
- JS_FreeValue(ctx, item);
- if (JS_IsException(next_promise)) {
- fail_reject1:
-@@ -47078,7 +47173,7 @@ static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val,
- goto done;
- }
-
--static __exception int perform_promise_then(JSContext *ctx,
-+static warn_unused int perform_promise_then(JSContext *ctx,
- JSValueConst promise,
- JSValueConst *resolve_reject,
- JSValueConst *cap_resolving_funcs)
-@@ -47196,7 +47291,7 @@ static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_va
- res = JS_Call(ctx, onFinally, JS_UNDEFINED, 0, NULL);
- if (JS_IsException(res))
- return res;
-- promise = js_promise_resolve(ctx, ctor, 1, (JSValueConst *)&res, 0);
-+ promise = js_promise_resolve(ctx, ctor, 1, &res, 0);
- JS_FreeValue(ctx, res);
- if (JS_IsException(promise))
- return promise;
-@@ -47211,7 +47306,7 @@ static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_va
- JS_FreeValue(ctx, promise);
- return then_func;
- }
-- ret = JS_InvokeFree(ctx, promise, JS_ATOM_then, 1, (JSValueConst *)&then_func);
-+ ret = JS_InvokeFree(ctx, promise, JS_ATOM_then, 1, &then_func);
- JS_FreeValue(ctx, then_func);
- return ret;
- }
-@@ -47288,7 +47383,7 @@ static JSValue js_async_from_sync_iterator_unwrap_func_create(JSContext *ctx,
- {
- JSValueConst func_data[1];
-
-- func_data[0] = (JSValueConst)JS_NewBool(ctx, done);
-+ func_data[0] = JS_NewBool(ctx, done);
- return JS_NewCFunctionData(ctx, js_async_from_sync_iterator_unwrap,
- 1, 0, 1, func_data);
- }
-@@ -47411,7 +47506,7 @@ static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst thi
- is_reject = 1;
- done_resolve:
- res2 = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED,
-- 1, (JSValueConst *)&err);
-+ 1, &err);
- JS_FreeValue(ctx, err);
- JS_FreeValue(ctx, res2);
- JS_FreeValue(ctx, resolving_funcs[0]);
-@@ -47423,7 +47518,7 @@ static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst thi
- int res;
-
- value_wrapper_promise = js_promise_resolve(ctx, ctx->promise_ctor,
-- 1, (JSValueConst *)&value, 0);
-+ 1, &value, 0);
- if (JS_IsException(value_wrapper_promise)) {
- JS_FreeValue(ctx, value);
- goto reject;
-@@ -47593,7 +47688,7 @@ static int isURIReserved(int c) {
- return c < 0x100 && memchr(";/?:@&=+$,#", c, sizeof(";/?:@&=+$,#") - 1) != NULL;
- }
-
--static int __attribute__((format(printf, 2, 3))) js_throw_URIError(JSContext *ctx, const char *fmt, ...)
-+static int FORMAT_ATTR(2, 3) js_throw_URIError(JSContext *ctx, const char *fmt, ...)
- {
- va_list ap;
-
-@@ -47894,7 +47989,7 @@ static int64_t floor_div(int64_t a, int64_t b) {
- static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv);
-
--static __exception int JS_ThisTimeValue(JSContext *ctx, double *valp, JSValueConst this_val)
-+static warn_unused int JS_ThisTimeValue(JSContext *ctx, double *valp, JSValueConst this_val)
- {
- if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
- JSObject *p = JS_VALUE_GET_OBJ(this_val);
-@@ -47954,7 +48049,7 @@ static int const month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
- static char const month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
- static char const day_names[] = "SunMonTueWedThuFriSat";
-
--static __exception int get_date_fields(JSContext *ctx, JSValueConst obj,
-+static warn_unused int get_date_fields(JSContext *ctx, JSValueConst obj,
- double fields[9], int is_local, int force)
- {
- double dval;
-@@ -48016,7 +48111,7 @@ static double time_clip(double t) {
-
- /* The spec mandates the use of 'double' and it fixes the order
- of the operations */
--static double set_date_fields(double fields[], int is_local) {
-+static double set_date_fields(const double fields[], int is_local) {
- int64_t y;
- double days, d, h, m1;
- int i, m, md;
-@@ -48213,9 +48308,17 @@ static JSValue get_date_string(JSContext *ctx, JSValueConst this_val,
-
- /* OS dependent: return the UTC time in ms since 1970. */
- static int64_t date_now(void) {
-+#ifdef _MSC_VER
-+ SYSTEMTIME st;
-+ GetSystemTime(&st);
-+ int64_t d;
-+ SystemTimeToFileTime(&st, (FILETIME *) &d);
-+ return d /= 10000;
-+#else
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
-+#endif
- }
-
- static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target,
-@@ -48246,7 +48349,7 @@ static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target,
- }
- v = JS_ToPrimitive(ctx, argv[0], HINT_NONE);
- if (JS_IsString(v)) {
-- dv = js_Date_parse(ctx, JS_UNDEFINED, 1, (JSValueConst *)&v);
-+ dv = js_Date_parse(ctx, JS_UNDEFINED, 1, &v);
- JS_FreeValue(ctx, v);
- if (JS_IsException(dv))
- return JS_EXCEPTION;
-@@ -48814,7 +48917,7 @@ void JS_AddIntrinsicDate(JSContext *ctx)
-
- void JS_AddIntrinsicEval(JSContext *ctx)
- {
-- ctx->eval_internal = __JS_EvalInternal;
-+ ctx->eval_internal = JS_EvalInternalImpl;
- }
-
- #ifdef CONFIG_BIGNUM
-@@ -50934,7 +51037,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
- JS_PROP_HAS_GET | JS_PROP_HAS_SET |
- JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE);
- JS_FreeValue(ctx, obj1);
-- JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, (JSValueConst *)&ctx->throw_type_error, 1));
-+ JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, &ctx->throw_type_error, 1));
-
- ctx->global_obj = JS_NewObject(ctx);
- ctx->global_var_obj = JS_NewObjectProto(ctx, JS_NULL);
-@@ -52090,7 +52193,7 @@ exception:
-
- #define special_indexOf 0
- #define special_lastIndexOf 1
--#define special_includes -1
-+#define special_includes (-1)
-
- static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int special)
-@@ -52157,8 +52260,7 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
- is_int = 1;
- v64 = JS_VALUE_GET_INT(argv[0]);
- d = v64;
-- } else
-- if (tag == JS_TAG_FLOAT64) {
-+ } else if (tag == JS_TAG_FLOAT64) {
- d = JS_VALUE_GET_FLOAT64(argv[0]);
- v64 = d;
- is_int = (v64 == d);
-@@ -52659,11 +52761,11 @@ static JSValue js_TA_get_uint64(JSContext *ctx, const void *a) {
- #endif
-
- static JSValue js_TA_get_float32(JSContext *ctx, const void *a) {
-- return __JS_NewFloat64(ctx, *(const float *)a);
-+ return JS_NewFloat64Impl(ctx, *(const float *)a);
- }
-
- static JSValue js_TA_get_float64(JSContext *ctx, const void *a) {
-- return __JS_NewFloat64(ctx, *(const double *)a);
-+ return JS_NewFloat64Impl(ctx, *(const double *)a);
- }
-
- struct TA_sort_context {
-@@ -52717,8 +52819,8 @@ static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) {
- psc->exception = 1;
- }
- done:
-- JS_FreeValue(ctx, (JSValue)argv[0]);
-- JS_FreeValue(ctx, (JSValue)argv[1]);
-+ JS_FreeValue(ctx, argv[0]);
-+ JS_FreeValue(ctx, argv[1]);
- }
- return cmp;
- }
-@@ -53285,7 +53387,7 @@ static JSValue js_dataview_getValue(JSContext *ctx,
- case JS_CLASS_INT8_ARRAY:
- return JS_NewInt32(ctx, *(int8_t *)ptr);
- case JS_CLASS_UINT8_ARRAY:
-- return JS_NewInt32(ctx, *(uint8_t *)ptr);
-+ return JS_NewInt32(ctx, *ptr);
- case JS_CLASS_INT16_ARRAY:
- v = get_u16(ptr);
- if (is_swap)
-@@ -53336,7 +53438,7 @@ static JSValue js_dataview_getValue(JSContext *ctx,
- if (is_swap)
- v = bswap32(v);
- u.i = v;
-- return __JS_NewFloat64(ctx, u.f);
-+ return JS_NewFloat64Impl(ctx, u.f);
- }
- case JS_CLASS_FLOAT64_ARRAY:
- {
-@@ -53347,7 +53449,7 @@ static JSValue js_dataview_getValue(JSContext *ctx,
- u.i = get_u64(ptr);
- if (is_swap)
- u.i = bswap64(u.i);
-- return __JS_NewFloat64(ctx, u.f);
-+ return JS_NewFloat64Impl(ctx, u.f);
- }
- default:
- abort();
-@@ -54059,3 +54161,155 @@ void JS_AddIntrinsicTypedArrays(JSContext *ctx)
- JS_AddIntrinsicAtomics(ctx);
- #endif
- }
-+
-+#ifndef NDEBUG
-+static void *watchedRefCount = NULL;
-+
-+void notifyRefCountIncrease(JSRefCountHeader *p)
-+{
-+ if (p == watchedRefCount)
-+ fprintf(stderr, "increasing ref count %d for %p\n", p->ref_count, watchedRefCount);
-+}
-+
-+void notifyRefCountDecrease(JSRefCountHeader *p)
-+{
-+ if (p == watchedRefCount)
-+ fprintf(stderr, "decreasing ref count %d for %p\n", p->ref_count, watchedRefCount);
-+}
-+
-+void watchRefCount(void *p)
-+{
-+ watchedRefCount = p;
-+}
-+#endif
-+
-+void setScopeLookup(JSContext *ctx, ScopeLookup *scopeLookup)
-+{
-+ ctx->scopeLookup = scopeLookup;
-+}
-+
-+void setFoundUndefinedHandler(JSContext *ctx, FoundUndefinedHandler *handler)
-+{
-+ ctx->handleUndefined = handler;
-+}
-+
-+void setFunctionEnteredHandler(JSContext *ctx, FunctionEnteredHandler *handler)
-+{
-+ ctx->handleFunctionEntered = handler;
-+}
-+
-+void setFunctionExitedHandler(JSContext *ctx, FunctionExitedHandler *handler)
-+{
-+ ctx->handleFunctionExited = handler;
-+}
-+
-+int isSimpleValue(JSValue v)
-+{
-+ JSObject *p;
-+ if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT)
-+ return 1;
-+ p = JS_VALUE_GET_OBJ(v);
-+ return p->class_id >= JS_CLASS_OBJECT && p->class_id <= JS_CLASS_BOOLEAN;
-+}
-+
-+JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *func,
-+ const char *name, int length,
-+ JSCFunctionEnum cproto, int magic)
-+{
-+ return JS_NewCFunction2(ctx, (JSCFunction *)func, name, length, cproto,
-+ magic);
-+}
-+
-+JSValue mkVal(int32_t tag, int32_t val)
-+{
-+ return (JSValue){ (JSValueUnion){ .int32 = val }, tag };
-+}
-+
-+JSValue mkPtr(int32_t tag, void *p)
-+{
-+ return (JSValue){ (JSValueUnion){ .ptr = p }, tag };
-+}
-+
-+void JS_FreeValue(JSContext *ctx, JSValue v) {
-+ if (JS_VALUE_HAS_REF_COUNT(v)) {
-+ JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
-+#ifndef NDEBUG
-+ notifyRefCountDecrease(p);
-+#endif
-+ if (--p->ref_count <= 0) {
-+ JS_FreeValueImpl(ctx, v);
-+ }
-+ }
-+}
-+void JS_FreeValueRT(JSRuntime *rt, JSValue v) {
-+ if (JS_VALUE_HAS_REF_COUNT(v)) {
-+ JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
-+#ifndef NDEBUG
-+ notifyRefCountDecrease(p);
-+#endif
-+ if (--p->ref_count <= 0) {
-+ JS_FreeValueRTImpl(rt, v);
-+ }
-+ }
-+}
-+JSValue JS_NewBool(JSContext *ctx, JS_BOOL val) {
-+ (void)ctx;
-+ return JS_MKVAL(JS_TAG_BOOL, (val != 0));
-+}
-+JSValue JS_NewInt32(JSContext *ctx, int32_t val) {
-+ (void)ctx;
-+ return JS_MKVAL(JS_TAG_INT, val);
-+}
-+JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val) {
-+ (void)ctx;
-+ return JS_MKVAL(JS_TAG_CATCH_OFFSET, val);
-+}
-+JSValue JS_NewInt64(JSContext *ctx, int64_t val) {
-+ JSValue v;
-+ if (val == (int32_t)val) {
-+ v = JS_NewInt32(ctx, (int32_t)val);
-+ } else {
-+ v = JS_NewFloat64Impl(ctx, (double)val);
-+ }
-+ return v;
-+}
-+JSValue JS_NewUint32(JSContext *ctx, uint32_t val) {
-+ JSValue v;
-+ if (val <= 0x7fffffff) {
-+ v = JS_NewInt32(ctx, val);
-+ } else {
-+ v = JS_NewFloat64Impl(ctx, val);
-+ }
-+ return v;
-+}
-+JSValue JS_NewFloat64(JSContext *ctx, double d) {
-+ JSValue v;
-+ int32_t val;
-+ union {
-+ double d;
-+ uint64_t u;
-+ } u, t;
-+ u.d = d;
-+ val = (int32_t)d;
-+ t.d = val;
-+ /* -0 cannot be represented as integer, so we compare the bit
-+ representation */
-+ if (u.u == t.u) {
-+ v = JS_MKVAL(JS_TAG_INT, val);
-+ } else {
-+ v = JS_NewFloat64Impl(ctx, d);
-+ }
-+ return v;
-+}
-+JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, const char *name,
-+ int length) {
-+ return JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_generic, 0);
-+}
-+
-+JS_BOOL JS_IsRegExp(JSContext *ctx, JSValue val)
-+{
-+ JSObject *p;
-+ if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
-+ return FALSE;
-+ return JS_VALUE_GET_OBJ(val)->class_id == JS_CLASS_REGEXP;
-+}
-diff --git a/quickjs.h b/quickjs.h
-index d4a5cd3..a5adf0c 100644
---- a/quickjs.h
-+++ b/quickjs.h
-@@ -215,15 +215,19 @@ typedef struct JSValue {
- #define JS_VALUE_GET_FLOAT64(v) ((v).u.float64)
- #define JS_VALUE_GET_PTR(v) ((v).u.ptr)
-
--#define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag }
--#define JS_MKPTR(tag, p) (JSValue){ (JSValueUnion){ .ptr = p }, tag }
-+JSValue mkVal(int32_t tag, int32_t val);
-+JSValue mkPtr(int32_t tag, void *p);
-+
-+#define JS_MKVAL(tag, val) mkVal(tag, val)
-+#define JS_MKPTR(tag, p) mkPtr(tag, p)
-
- #define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64)
-
- #define JS_NAN (JSValue){ .u.float64 = JS_FLOAT64_NAN, JS_TAG_FLOAT64 }
-
--static inline JSValue __JS_NewFloat64(JSContext *ctx, double d)
-+static inline JSValue JS_NewFloat64Impl(JSContext *ctx, double d)
- {
-+ (void) ctx;
- JSValue v;
- v.tag = JS_TAG_FLOAT64;
- v.u.float64 = d;
-@@ -502,66 +506,14 @@ int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id);
-
- /* value handling */
-
--static js_force_inline JSValue JS_NewBool(JSContext *ctx, JS_BOOL val)
--{
-- return JS_MKVAL(JS_TAG_BOOL, (val != 0));
--}
--
--static js_force_inline JSValue JS_NewInt32(JSContext *ctx, int32_t val)
--{
-- return JS_MKVAL(JS_TAG_INT, val);
--}
--
--static js_force_inline JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val)
--{
-- return JS_MKVAL(JS_TAG_CATCH_OFFSET, val);
--}
--
--static js_force_inline JSValue JS_NewInt64(JSContext *ctx, int64_t val)
--{
-- JSValue v;
-- if (val == (int32_t)val) {
-- v = JS_NewInt32(ctx, val);
-- } else {
-- v = __JS_NewFloat64(ctx, val);
-- }
-- return v;
--}
--
--static js_force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val)
--{
-- JSValue v;
-- if (val <= 0x7fffffff) {
-- v = JS_NewInt32(ctx, val);
-- } else {
-- v = __JS_NewFloat64(ctx, val);
-- }
-- return v;
--}
--
-+JSValue JS_NewBool(JSContext *ctx, JS_BOOL val);
-+JSValue JS_NewInt32(JSContext *ctx, int32_t val);
-+JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val);
-+JSValue JS_NewInt64(JSContext *ctx, int64_t val);
-+JSValue JS_NewUint32(JSContext *ctx, uint32_t val);
- JSValue JS_NewBigInt64(JSContext *ctx, int64_t v);
- JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v);
--
--static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double d)
--{
-- JSValue v;
-- int32_t val;
-- union {
-- double d;
-- uint64_t u;
-- } u, t;
-- u.d = d;
-- val = (int32_t)d;
-- t.d = val;
-- /* -0 cannot be represented as integer, so we compare the bit
-- representation */
-- if (u.u == t.u) {
-- v = JS_MKVAL(JS_TAG_INT, val);
-- } else {
-- v = __JS_NewFloat64(ctx, d);
-- }
-- return v;
--}
-+JSValue JS_NewFloat64(JSContext *ctx, double d);
-
- static inline JS_BOOL JS_IsNumber(JSValueConst v)
- {
-@@ -571,6 +523,7 @@ static inline JS_BOOL JS_IsNumber(JSValueConst v)
-
- static inline JS_BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v)
- {
-+ (void) ctx;
- int tag = JS_VALUE_GET_TAG(v);
- return tag == JS_TAG_BIG_INT;
- }
-@@ -639,43 +592,38 @@ JSValue __js_printf_like(2, 3) JS_ThrowRangeError(JSContext *ctx, const char *fm
- JSValue __js_printf_like(2, 3) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...);
- JSValue JS_ThrowOutOfMemory(JSContext *ctx);
-
--void __JS_FreeValue(JSContext *ctx, JSValue v);
--static inline void JS_FreeValue(JSContext *ctx, JSValue v)
--{
-- if (JS_VALUE_HAS_REF_COUNT(v)) {
-- JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
-- if (--p->ref_count <= 0) {
-- __JS_FreeValue(ctx, v);
-- }
-- }
--}
--void __JS_FreeValueRT(JSRuntime *rt, JSValue v);
--static inline void JS_FreeValueRT(JSRuntime *rt, JSValue v)
--{
-- if (JS_VALUE_HAS_REF_COUNT(v)) {
-- JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
-- if (--p->ref_count <= 0) {
-- __JS_FreeValueRT(rt, v);
-- }
-- }
--}
-+#ifndef NDEBUG
-+void notifyRefCountIncrease(JSRefCountHeader *p);
-+void notifyRefCountDecrease(JSRefCountHeader *p);
-+#endif
-+
-+void JS_FreeValue(JSContext *ctx, JSValue v);
-+void JS_FreeValueRT(JSRuntime *rt, JSValue v);
-
- static inline JSValue JS_DupValue(JSContext *ctx, JSValueConst v)
- {
-+ (void) ctx;
- if (JS_VALUE_HAS_REF_COUNT(v)) {
- JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
-+#ifndef NDEBUG
-+ notifyRefCountIncrease(p);
-+#endif
- p->ref_count++;
- }
-- return (JSValue)v;
-+ return v;
- }
-
- static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v)
- {
-+ (void) rt;
- if (JS_VALUE_HAS_REF_COUNT(v)) {
- JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
-+#ifndef NDEBUG
-+ notifyRefCountIncrease(p);
-+#endif
- p->ref_count++;
- }
-- return (JSValue)v;
-+ return v;
- }
-
- int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */
-@@ -714,6 +662,7 @@ JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto);
- JSValue JS_NewObject(JSContext *ctx);
-
- JS_BOOL JS_IsFunction(JSContext* ctx, JSValueConst val);
-+JS_BOOL JS_IsRegExp(JSContext* ctx, JSValueConst val);
- JS_BOOL JS_IsConstructor(JSContext* ctx, JSValueConst val);
- JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val);
-
-@@ -783,7 +732,7 @@ JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
- /* same as JS_Eval() but with an explicit 'this_obj' parameter */
- JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,
- const char *input, size_t input_len,
-- const char *filename, int eval_flags);
-+ const char *filename, int line, int eval_flags);
- JSValue JS_GetGlobalObject(JSContext *ctx);
- int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj);
- int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
-@@ -945,18 +894,11 @@ JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
- int length, int magic, int data_len,
- JSValueConst *data);
-
--static inline JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, const char *name,
-- int length)
--{
-- return JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_generic, 0);
--}
-+JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, const char *name,
-+ int length);
-
--static inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *func,
-- const char *name,
-- int length, JSCFunctionEnum cproto, int magic)
--{
-- return JS_NewCFunction2(ctx, (JSCFunction *)func, name, length, cproto, magic);
--}
-+JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *func,
-+ const char *name, int length, JSCFunctionEnum cproto, int magic);
- void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj,
- JSValueConst proto);
-
-@@ -1039,6 +981,35 @@ int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name,
- int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
- const JSCFunctionListEntry *tab, int len);
-
-+
-+/* Qbs extensions */
-+struct LookupResult
-+{
-+ JSValue value;
-+ JSValue scope;
-+ int useResult;
-+};
-+typedef struct LookupResult ScopeLookup(JSContext *ctx, JSAtom prop);
-+void setScopeLookup(JSContext *ctx, ScopeLookup *scopeLookup);
-+
-+// Alternative: Request with throw in script engine
-+typedef void FoundUndefinedHandler(JSContext *ctx);
-+void setFoundUndefinedHandler(JSContext *ctx, FoundUndefinedHandler *handler);
-+
-+typedef void FunctionEnteredHandler(JSContext *ctx, JSValue this_val);
-+typedef void FunctionExitedHandler(JSContext *ctx);
-+void setFunctionEnteredHandler(JSContext *ctx, FunctionEnteredHandler *handler);
-+void setFunctionExitedHandler(JSContext *ctx, FunctionExitedHandler *handler);
-+int isSimpleValue(JSValue v);
-+
-+#ifndef NDEBUG
-+void watchRefCount(void *p);
-+#endif
-+
-+void build_backtrace(JSContext *ctx, JSValueConst error_obj,
-+ const char *filename, int line_num,
-+ int backtrace_flags);
-+
- #undef js_unlikely
- #undef js_force_inline
-
diff --git a/src/shared/quickjs/quickjs.h b/src/shared/quickjs/quickjs.h
index a5adf0cd2..3a22f5b7b 100644
--- a/src/shared/quickjs/quickjs.h
+++ b/src/shared/quickjs/quickjs.h
@@ -158,6 +158,7 @@ static inline double JS_VALUE_GET_FLOAT64(JSValue v)
static inline JSValue __JS_NewFloat64(JSContext *ctx, double d)
{
+ (void) ctx;
union {
double d;
uint64_t u64;
@@ -225,7 +226,7 @@ JSValue mkPtr(int32_t tag, void *p);
#define JS_NAN (JSValue){ .u.float64 = JS_FLOAT64_NAN, JS_TAG_FLOAT64 }
-static inline JSValue JS_NewFloat64Impl(JSContext *ctx, double d)
+static inline JSValue __JS_NewFloat64(JSContext *ctx, double d)
{
(void) ctx;
JSValue v;
@@ -311,6 +312,9 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
#define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5)
/* don't include the stack frames before this eval in the Error() backtraces */
#define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6)
+/* allow top-level await in normal script. JS_Eval() returns a
+ promise. Only allowed with JS_EVAL_TYPE_GLOBAL */
+#define JS_EVAL_FLAG_ASYNC (1 << 7)
typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv);
typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic);
@@ -500,7 +504,10 @@ typedef struct JSClassDef {
JSClassExoticMethods *exotic;
} JSClassDef;
+#define JS_INVALID_CLASS_ID 0
JSClassID JS_NewClassID(JSClassID *pclass_id);
+/* Returns the class ID if `v` is an object, otherwise returns JS_INVALID_CLASS_ID. */
+JSClassID JS_GetClassID(JSValue v);
int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def);
int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id);
@@ -513,6 +520,7 @@ JSValue JS_NewInt64(JSContext *ctx, int64_t val);
JSValue JS_NewUint32(JSContext *ctx, uint32_t val);
JSValue JS_NewBigInt64(JSContext *ctx, int64_t v);
JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v);
+
JSValue JS_NewFloat64(JSContext *ctx, double d);
static inline JS_BOOL JS_IsNumber(JSValueConst v)
@@ -582,7 +590,9 @@ static inline JS_BOOL JS_IsObject(JSValueConst v)
JSValue JS_Throw(JSContext *ctx, JSValue obj);
JSValue JS_GetException(JSContext *ctx);
+JS_BOOL JS_HasException(JSContext *ctx);
JS_BOOL JS_IsError(JSContext *ctx, JSValueConst val);
+void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, JS_BOOL flag);
void JS_ResetUncatchableError(JSContext *ctx);
JSValue JS_NewError(JSContext *ctx);
JSValue __js_printf_like(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...);
@@ -626,6 +636,10 @@ static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v)
return v;
}
+JS_BOOL JS_StrictEq(JSContext *ctx, JSValueConst op1, JSValueConst op2);
+JS_BOOL JS_SameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2);
+JS_BOOL JS_SameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2);
+
int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */
int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val);
static inline int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val)
@@ -665,10 +679,14 @@ JS_BOOL JS_IsFunction(JSContext* ctx, JSValueConst val);
JS_BOOL JS_IsRegExp(JSContext* ctx, JSValueConst val);
JS_BOOL JS_IsConstructor(JSContext* ctx, JSValueConst val);
JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val);
+JS_BOOL JS_IsArrayBuffer(JSValueConst v);
JSValue JS_NewArray(JSContext *ctx);
int JS_IsArray(JSContext *ctx, JSValueConst val);
+JSValue JS_NewDate(JSContext *ctx, double epoch_ms);
+JS_BOOL JS_IsDate(JSValueConst v);
+
JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
JSAtom prop, JSValueConst receiver,
JS_BOOL throw_ref_error);
@@ -682,13 +700,13 @@ JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj,
JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
uint32_t idx);
-int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj,
- JSAtom prop, JSValue val,
+int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj,
+ JSAtom prop, JSValue val, JSValueConst this_obj,
int flags);
static inline int JS_SetProperty(JSContext *ctx, JSValueConst this_obj,
JSAtom prop, JSValue val)
{
- return JS_SetPropertyInternal(ctx, this_obj, prop, val, JS_PROP_THROW);
+ return JS_SetPropertyInternal(ctx, this_obj, prop, val, this_obj, JS_PROP_THROW);
}
int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
uint32_t idx, JSValue val);
@@ -703,6 +721,8 @@ int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags);
int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val);
JSValue JS_GetPrototype(JSContext *ctx, JSValueConst val);
+JSValue JS_ObjectSeal(JSContext *ctx, JSValueConst obj, int freeze);
+
#define JS_GPN_STRING_MASK (1 << 0)
#define JS_GPN_SYMBOL_MASK (1 << 1)
#define JS_GPN_PRIVATE_MASK (1 << 2)
@@ -767,6 +787,23 @@ JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len,
JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len);
void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj);
uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj);
+
+typedef enum JSTypedArrayEnum {
+ JS_TYPED_ARRAY_UINT8C = 0,
+ JS_TYPED_ARRAY_INT8,
+ JS_TYPED_ARRAY_UINT8,
+ JS_TYPED_ARRAY_INT16,
+ JS_TYPED_ARRAY_UINT16,
+ JS_TYPED_ARRAY_INT32,
+ JS_TYPED_ARRAY_UINT32,
+ JS_TYPED_ARRAY_BIG_INT64,
+ JS_TYPED_ARRAY_BIG_UINT64,
+ JS_TYPED_ARRAY_FLOAT32,
+ JS_TYPED_ARRAY_FLOAT64,
+} JSTypedArrayEnum;
+
+JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv,
+ JSTypedArrayEnum array_type);
JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,
size_t *pbyte_offset,
size_t *pbyte_length,
@@ -780,7 +817,15 @@ typedef struct {
void JS_SetSharedArrayBufferFunctions(JSRuntime *rt,
const JSSharedArrayBufferFunctions *sf);
+typedef enum JSPromiseStateEnum {
+ JS_PROMISE_PENDING,
+ JS_PROMISE_FULFILLED,
+ JS_PROMISE_REJECTED,
+} JSPromiseStateEnum;
+
JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs);
+JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise);
+JSValue JS_PromiseResult(JSContext *ctx, JSValue promise);
/* is_handled = TRUE means that the rejection is handled */
typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise,
@@ -814,6 +859,7 @@ void JS_SetModuleLoaderFunc(JSRuntime *rt,
/* return the import.meta object of a module */
JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m);
JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m);
+JSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m);
/* JS Job support */
@@ -851,8 +897,8 @@ int JS_ResolveModule(JSContext *ctx, JSValueConst obj);
/* only exported for os.Worker() */
JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels);
/* only exported for os.Worker() */
-JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
- const char *filename);
+JSValue JS_LoadModule(JSContext *ctx, const char *basename,
+ const char *filename);
/* C function definition */
typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */
diff --git a/src/shared/quickjs/quickjs.qbs b/src/shared/quickjs/quickjs.qbs
index 4c8112ac9..bdce37979 100644
--- a/src/shared/quickjs/quickjs.qbs
+++ b/src/shared/quickjs/quickjs.qbs
@@ -12,6 +12,8 @@ StaticLibrary {
files: [
"cutils.c",
"cutils.h",
+ "libbf.c",
+ "libbf.h",
"libregexp-opcode.h",
"libregexp.c",
"libregexp.h",
@@ -22,12 +24,11 @@ StaticLibrary {
"quickjs-atom.h",
"quickjs-opcode.h",
"quickjs.c",
- "quickjs.diff",
"quickjs.h",
]
Export {
Depends { name: "cpp" }
- cpp.includePaths: [exportingProduct.sourceDirectory]
+ cpp.systemIncludePaths: [exportingProduct.sourceDirectory]
}
}