mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Javascript: Update choc dependency
This fixes an issue when evaluating javascript on macOS while address sanitiser and undefined behaviour sanitiser are both enabled
This commit is contained in:
parent
b108fe26c3
commit
24d33759b8
39 changed files with 564 additions and 484 deletions
|
|
@ -1,12 +0,0 @@
|
|||
The files in this directory were downloaded from the choc repository at
|
||||
https://github.com/Tracktion/choc.
|
||||
|
||||
In order to avoid exposing any symbols in the choc implementation, the files were modified by
|
||||
prepending all `namespace choc...` lines with `namespace {`, and by adding corresponding closing
|
||||
brackets as well.
|
||||
|
||||
Enclosing all choc definitions in an anonymous namespace allows JUCE based projects to use an
|
||||
external copy of choc without running into multiply defined symbol compilation errors.
|
||||
|
||||
By placing the anonymous namespace encapsulation inside the choc header files we avoid the issue of
|
||||
including the system headers in the namespace as well.
|
||||
|
|
@ -27,8 +27,6 @@
|
|||
#include <exception>
|
||||
#include "../platform/choc_Assert.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace choc::value
|
||||
{
|
||||
|
||||
|
|
@ -430,19 +428,36 @@ public:
|
|||
//==============================================================================
|
||||
/** A simple implementation of StringDictionary.
|
||||
This should have good performance for typical-sized dictionaries.
|
||||
Adding new strings will require O(n) time where n = dictionary size, but
|
||||
Adding new strings will require O(log n) time where n = dictionary size, but
|
||||
retrieving the string for a handle is fast with O(1).
|
||||
*/
|
||||
struct SimpleStringDictionary : public StringDictionary
|
||||
{
|
||||
SimpleStringDictionary() = default;
|
||||
SimpleStringDictionary (const SimpleStringDictionary& other) : strings (other.strings), stringMap (other.stringMap) {}
|
||||
SimpleStringDictionary (SimpleStringDictionary&& other) : strings (std::move (other.strings)), stringMap (std::move (other.stringMap)) {}
|
||||
SimpleStringDictionary& operator= (const SimpleStringDictionary& other) { strings = other.strings; stringMap = other.stringMap; return *this; }
|
||||
SimpleStringDictionary& operator= (SimpleStringDictionary&& other) { strings = std::move (other.strings); stringMap = std::move (other.stringMap); return *this; }
|
||||
|
||||
Handle getHandleForString (std::string_view) override;
|
||||
std::string_view getStringForHandle (Handle handle) const override;
|
||||
|
||||
bool empty() const { return strings.empty(); }
|
||||
void clear();
|
||||
|
||||
size_t getRawDataSize() const { return strings.size(); }
|
||||
const char* getRawData() const { return strings.data(); }
|
||||
|
||||
void setRawData (const void*, size_t);
|
||||
|
||||
private:
|
||||
std::pair<std::vector<uint32_t>::const_iterator, bool> findGreaterThanOrEqual (std::string_view) const;
|
||||
|
||||
/// The strings are stored in a single chunk, which can be saved and
|
||||
/// reloaded if necessary.
|
||||
/// reloaded if necessary. The stringMap is a sorted vector of handles
|
||||
/// supporting fast lookup of strings in the map
|
||||
std::vector<char> strings;
|
||||
std::vector<uint32_t> stringMap;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -1654,15 +1669,17 @@ inline int Type::getObjectMemberIndex (std::string_view name) const
|
|||
template <typename PrimitiveType>
|
||||
inline constexpr Type::MainType Type::selectMainType()
|
||||
{
|
||||
if constexpr (std::is_same<const PrimitiveType, const int32_t>::value) return MainType::int32;
|
||||
if constexpr (std::is_same<const PrimitiveType, const int64_t>::value) return MainType::int64;
|
||||
if constexpr (std::is_same<const PrimitiveType, const float>::value) return MainType::float32;
|
||||
if constexpr (std::is_same<const PrimitiveType, const double>::value) return MainType::float64;
|
||||
if constexpr (std::is_same<const PrimitiveType, const bool>::value) return MainType::boolean;
|
||||
if constexpr (std::is_same<const PrimitiveType, const char* const>::value) return MainType::string;
|
||||
if constexpr (std::is_same<const PrimitiveType, const std::string>::value) return MainType::string;
|
||||
Type::MainType result = MainType::void_;
|
||||
|
||||
return MainType::void_;
|
||||
if constexpr (std::is_same<const PrimitiveType, const int32_t>::value) result = MainType::int32;
|
||||
else if constexpr (std::is_same<const PrimitiveType, const int64_t>::value) result = MainType::int64;
|
||||
else if constexpr (std::is_same<const PrimitiveType, const float>::value) result = MainType::float32;
|
||||
else if constexpr (std::is_same<const PrimitiveType, const double>::value) result = MainType::float64;
|
||||
else if constexpr (std::is_same<const PrimitiveType, const bool>::value) result = MainType::boolean;
|
||||
else if constexpr (std::is_same<const PrimitiveType, const char* const>::value) result = MainType::string;
|
||||
else if constexpr (std::is_same<const PrimitiveType, const std::string>::value) result = MainType::string;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename PrimitiveType>
|
||||
|
|
@ -2302,7 +2319,11 @@ inline StringDictionary::Handle ValueView::getStringHandle() const
|
|||
|
||||
inline std::string_view ValueView::getString() const
|
||||
{
|
||||
check (stringDictionary != nullptr, "No string dictionary supplied");
|
||||
// To satisfy the MSVC code analyser this check needs to be handled directly
|
||||
// from this function
|
||||
if (stringDictionary == nullptr)
|
||||
throwError ("No string dictionary supplied");
|
||||
|
||||
return stringDictionary->getStringForHandle (getStringHandle());
|
||||
}
|
||||
|
||||
|
|
@ -2409,21 +2430,43 @@ void ValueView::serialise (OutputStream& output) const
|
|||
if (type.isVoid())
|
||||
return;
|
||||
|
||||
auto dataSize = type.getValueDataSize();
|
||||
auto dataSize = type.getValueDataSize();
|
||||
check (dataSize > 0, "Invalid data size");
|
||||
|
||||
if (stringDictionary == nullptr || ! type.usesStrings())
|
||||
{
|
||||
output.write (data, dataSize);
|
||||
return;
|
||||
}
|
||||
if (stringDictionary == nullptr || ! type.usesStrings())
|
||||
{
|
||||
output.write (data, dataSize);
|
||||
return;
|
||||
}
|
||||
|
||||
static constexpr uint32_t maximumSize = 16384;
|
||||
uint8_t* localCopy = nullptr;
|
||||
|
||||
if (dataSize > maximumSize)
|
||||
throwError ("Out of local scratch space");
|
||||
#if _MSC_VER
|
||||
|
||||
uint8_t localCopy[maximumSize];
|
||||
std::memcpy (localCopy, data, dataSize);
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wlanguage-extension-token"
|
||||
#endif
|
||||
|
||||
__try
|
||||
{
|
||||
localCopy = (uint8_t*) _alloca (dataSize);
|
||||
}
|
||||
__except (GetExceptionCode() == STATUS_STACK_OVERFLOW)
|
||||
{
|
||||
throwError ("Stack overflow");
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#else
|
||||
localCopy = (uint8_t*) alloca (dataSize);
|
||||
#endif
|
||||
|
||||
check (localCopy != nullptr, "Stack allocation failed");
|
||||
std::memcpy (localCopy, data, dataSize);
|
||||
|
||||
static constexpr uint32_t maxStrings = 128;
|
||||
uint32_t numStrings = 0, stringDataSize = 0;
|
||||
|
|
@ -2918,11 +2961,10 @@ template <typename OutputStream> void Value::serialise (OutputStream& o) const
|
|||
{
|
||||
o.write (getRawData(), value.type.getValueDataSize());
|
||||
|
||||
if (auto stringDataSize = static_cast<uint32_t> (dictionary.strings.size()))
|
||||
if (auto stringDataSize = static_cast<uint32_t> (dictionary.getRawDataSize()))
|
||||
{
|
||||
CHOC_ASSERT (dictionary.strings.back() == 0);
|
||||
Type::SerialisationHelpers::writeVariableLengthInt (o, stringDataSize);
|
||||
o.write (dictionary.strings.data(), stringDataSize);
|
||||
o.write (dictionary.getRawData(), stringDataSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2947,9 +2989,7 @@ inline Value Value::deserialise (InputData& input)
|
|||
{
|
||||
auto stringDataSize = Type::SerialisationHelpers::readVariableLengthInt (input);
|
||||
Type::SerialisationHelpers::expect (stringDataSize <= static_cast<uint32_t> (input.end - input.start));
|
||||
v.dictionary.strings.resize (stringDataSize);
|
||||
std::memcpy (v.dictionary.strings.data(), input.start, stringDataSize);
|
||||
Type::SerialisationHelpers::expect (v.dictionary.strings.back() == 0);
|
||||
v.dictionary.setRawData (input.start, stringDataSize);
|
||||
}
|
||||
|
||||
return v;
|
||||
|
|
@ -3207,20 +3247,20 @@ inline SimpleStringDictionary::Handle SimpleStringDictionary::getHandleForString
|
|||
if (text.empty())
|
||||
return {};
|
||||
|
||||
for (size_t i = 0; i < strings.size(); ++i)
|
||||
{
|
||||
std::string_view sv (strings.data() + i);
|
||||
auto i = findGreaterThanOrEqual (text);
|
||||
|
||||
if (text == sv)
|
||||
return { static_cast<decltype(Handle::handle)> (i + 1) };
|
||||
|
||||
i += sv.length();
|
||||
}
|
||||
if (i.second)
|
||||
return { *i.first };
|
||||
|
||||
auto newHandle = static_cast<decltype(Handle::handle)> (strings.size() + 1);
|
||||
strings.reserve (strings.size() + text.length() + 1);
|
||||
|
||||
if (strings.size() > 100 && (strings.capacity() < (strings.size() + text.length() + 1)))
|
||||
strings.reserve (strings.size() + 1000);
|
||||
|
||||
strings.insert (strings.end(), text.begin(), text.end());
|
||||
strings.push_back (0);
|
||||
|
||||
stringMap.insert (i.first, newHandle);
|
||||
return { newHandle };
|
||||
}
|
||||
|
||||
|
|
@ -3235,9 +3275,41 @@ inline std::string_view SimpleStringDictionary::getStringForHandle (Handle handl
|
|||
return std::string_view (strings.data() + (handle.handle - 1));
|
||||
}
|
||||
|
||||
inline void SimpleStringDictionary::clear() { strings.clear(); }
|
||||
inline void SimpleStringDictionary::clear() { strings.clear(); stringMap.clear(); }
|
||||
|
||||
inline void SimpleStringDictionary::setRawData (const void* p, size_t n)
|
||||
{
|
||||
strings.resize (n);
|
||||
std::memcpy (strings.data(), p, n);
|
||||
|
||||
// Populate string map
|
||||
for (size_t i = 0; i < strings.size(); ++i)
|
||||
{
|
||||
std::string_view sv (strings.data() + i);
|
||||
auto v = findGreaterThanOrEqual (sv);
|
||||
stringMap.insert (v.first, static_cast<uint32_t> (i));
|
||||
i += sv.length();
|
||||
}
|
||||
}
|
||||
|
||||
inline std::pair<std::vector<uint32_t>::const_iterator, bool> SimpleStringDictionary::findGreaterThanOrEqual (std::string_view v) const
|
||||
{
|
||||
bool exactMatch = false;
|
||||
|
||||
auto it = std::lower_bound (stringMap.begin(), stringMap.end(), v, [&] (uint32_t i, std::string_view sv) -> bool
|
||||
{
|
||||
auto c = sv.compare (getStringForHandle ( { i }));
|
||||
|
||||
if (c == 0)
|
||||
exactMatch = true;
|
||||
|
||||
return c > 0;
|
||||
});
|
||||
|
||||
return std::pair (it, exactMatch);
|
||||
}
|
||||
|
||||
} // namespace choc::value
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
#endif // CHOC_VALUE_POOL_HEADER_INCLUDED
|
||||
|
|
|
|||
|
|
@ -33,8 +33,6 @@
|
|||
choc::javascript::createQuickJSContext() to create a context for running
|
||||
javascript code.
|
||||
*/
|
||||
namespace
|
||||
{
|
||||
namespace choc::javascript
|
||||
{
|
||||
/// This is thrown by any javascript functions that need to report an error
|
||||
|
|
@ -95,23 +93,40 @@ namespace choc::javascript
|
|||
Context& operator= (Context&&);
|
||||
~Context();
|
||||
|
||||
/// Returns true if the context is valid.
|
||||
operator bool() const { return pimpl != nullptr; }
|
||||
|
||||
//==============================================================================
|
||||
/// This callback is used by the run() method.
|
||||
using CompletionHandler = std::function<void(const std::string& error,
|
||||
const choc::value::ValueView& result)>;
|
||||
|
||||
/// Executes some javascript asynchronously.
|
||||
/// If a CompletionHandler callback is provided, it will be called asynchronously
|
||||
/// with the return value and any errors that occurred. Note that if you want to execute
|
||||
/// the script as a module, use runModule() instead.
|
||||
void run (const std::string& javascriptCode,
|
||||
CompletionHandler handleResult = {});
|
||||
|
||||
/// When parsing modules, this function is expected to take a path to a module, and
|
||||
/// to return the content of that module, or an empty optional if not found.
|
||||
using ReadModuleContentFn = std::function<std::optional<std::string>(std::string_view)>;
|
||||
|
||||
//==============================================================================
|
||||
/// Evaluates the given chunk of javascript.
|
||||
/// If there are any parse errors, this will throw a choc::javascript::Error exception.
|
||||
/// If the engine supports modules, then providing a value for the resolveModuleContent
|
||||
/// function will treat the code as a module and will call your function to read the
|
||||
/// content of any dependencies.
|
||||
/// None of the methods in this class are either thread-safe or realtime-safe, so you'll
|
||||
/// need to organise your own locking if you're calling into a single Context from
|
||||
/// multiple threads.
|
||||
choc::value::Value evaluate (const std::string& javascriptCode,
|
||||
ReadModuleContentFn* resolveModuleContent = nullptr);
|
||||
/// This callback will asynchronously parse the script as a module, and will use the
|
||||
/// ReadModuleContentFn functor to resolve any imported modules that it needs. If a
|
||||
/// CompletionHandler callback is provided, it will be called asynchronously with the
|
||||
/// return value and any errors that occurred.
|
||||
/// NB: Not all engines support modules.
|
||||
void runModule (const std::string& moduleCode,
|
||||
ReadModuleContentFn,
|
||||
CompletionHandler handleResult = {});
|
||||
|
||||
/// Attempts to invoke a global function with no arguments.
|
||||
/// Evaluates a javascript expression synchronously, and returns the result.
|
||||
/// If there are any parse errors, this will throw a choc::javascript::Error exception.
|
||||
/// Note that if you want to execute the script as a module, use runModule() instead.
|
||||
choc::value::Value evaluateExpression (const std::string& javascriptCode);
|
||||
|
||||
/// Attempts to synchronously invoke a global function with no arguments.
|
||||
/// Any errors will throw a choc::javascript::Error exception.
|
||||
/// None of the methods in this class are either thread-safe or realtime-safe, so you'll
|
||||
/// need to organise your own locking if you're calling into a single Context from
|
||||
|
|
@ -153,8 +168,6 @@ namespace choc::javascript
|
|||
/// @internal
|
||||
Context (std::unique_ptr<Pimpl>);
|
||||
|
||||
Pimpl* getPimpl() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Pimpl> pimpl;
|
||||
};
|
||||
|
|
@ -172,8 +185,13 @@ namespace choc::javascript
|
|||
/// make sure that your project also has the V8 header folder in its
|
||||
/// search path, and that you statically link the appropriate V8 libs.
|
||||
Context createV8Context();
|
||||
|
||||
//==============================================================================
|
||||
/// Sanitises a string to provide a version of it that is safe for use as a
|
||||
/// javascript identifier. This involves removing/replacing any illegal
|
||||
/// characters and modifying the string to avoid clashes with reserved words.
|
||||
std::string makeSafeIdentifier (std::string name);
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -187,8 +205,6 @@ namespace choc::javascript
|
|||
//
|
||||
//==============================================================================
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace choc::javascript
|
||||
{
|
||||
|
||||
|
|
@ -207,7 +223,8 @@ struct Context::Pimpl
|
|||
virtual ~Pimpl() = default;
|
||||
|
||||
virtual void registerFunction (const std::string&, NativeFunction) = 0;
|
||||
virtual choc::value::Value evaluate (const std::string&, ReadModuleContentFn*) = 0;
|
||||
virtual choc::value::Value evaluateExpression (const std::string&) = 0;
|
||||
virtual void run (const std::string&, ReadModuleContentFn*, CompletionHandler) = 0;
|
||||
virtual void prepareForCall (std::string_view, uint32_t numArgs) = 0;
|
||||
virtual choc::value::Value performCall() = 0;
|
||||
virtual void pushObjectOrArray (const choc::value::ValueView&) = 0;
|
||||
|
|
@ -277,10 +294,22 @@ inline void Context::registerFunction (const std::string& name, NativeFunction f
|
|||
pimpl->registerFunction (name, std::move (fn));
|
||||
}
|
||||
|
||||
inline choc::value::Value Context::evaluate (const std::string& javascriptCode, ReadModuleContentFn* resolveModule)
|
||||
inline choc::value::Value Context::evaluateExpression (const std::string& javascriptCode)
|
||||
{
|
||||
CHOC_ASSERT (pimpl != nullptr); // cannot call this on a moved-from context!
|
||||
return pimpl->evaluate (javascriptCode, resolveModule);
|
||||
return pimpl->evaluateExpression (javascriptCode);
|
||||
}
|
||||
|
||||
inline void Context::run (const std::string& javascriptCode, CompletionHandler handleResult)
|
||||
{
|
||||
CHOC_ASSERT (pimpl != nullptr); // cannot call this on a moved-from context!
|
||||
pimpl->run (javascriptCode, nullptr, std::move (handleResult));
|
||||
}
|
||||
|
||||
inline void Context::runModule (const std::string& moduleCode, ReadModuleContentFn readModule, CompletionHandler handleResult)
|
||||
{
|
||||
CHOC_ASSERT (pimpl != nullptr); // cannot call this on a moved-from context!
|
||||
pimpl->run (moduleCode, std::addressof (readModule), std::move (handleResult));
|
||||
}
|
||||
|
||||
inline void Context::pumpMessageLoop()
|
||||
|
|
@ -289,13 +318,40 @@ inline void Context::pumpMessageLoop()
|
|||
pimpl->pumpMessageLoop();
|
||||
}
|
||||
|
||||
Context::Pimpl* Context::getPimpl() const
|
||||
inline std::string makeSafeIdentifier (std::string s)
|
||||
{
|
||||
return pimpl.get();
|
||||
constexpr static std::string_view reservedWords[] =
|
||||
{
|
||||
"abstract", "arguments", "await", "boolean", "break", "byte", "case", "catch",
|
||||
"char", "class", "const", "continue", "debugger", "default", "delete", "do",
|
||||
"double", "else", "enum", "eval", "export", "extends", "false", "final",
|
||||
"finally", "float", "for", "function", "goto", "if", "implements", "import",
|
||||
"in", "instanceof", "int", "interface", "let", "long", "native", "new",
|
||||
"null", "package", "private", "protected", "public", "return", "short", "static",
|
||||
"super", "switch", "synchronized", "this", "throw", "throws", "transient", "true",
|
||||
"try", "typeof", "var", "void", "volatile", "while", "with", "yield"
|
||||
};
|
||||
|
||||
for (auto& c : s)
|
||||
if (std::string_view (" ,./;:").find (c) != std::string_view::npos)
|
||||
c = '_';
|
||||
|
||||
s.erase (std::remove_if (s.begin(), s.end(), [&] (char c)
|
||||
{
|
||||
return ! ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9'));
|
||||
}), s.end());
|
||||
|
||||
if (s[0] >= '0' && s[0] <= '9') // Identifiers can't start with a digit
|
||||
s = "_" + s;
|
||||
|
||||
for (auto keyword : reservedWords)
|
||||
if (s == keyword)
|
||||
return s + "_";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace choc::javascript
|
||||
} // anonymous namespace
|
||||
|
||||
#endif // CHOC_JAVASCRIPT_HEADER_INCLUDED
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -30,14 +30,12 @@
|
|||
#pragma intrinsic (_BitScanReverse64)
|
||||
#endif
|
||||
|
||||
#ifdef _M_X64
|
||||
#if defined (_M_X64) && ! defined (_M_ARM64EC)
|
||||
#pragma intrinsic (_umul128)
|
||||
#define CHOC_HAS_UMUL128 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace choc::math
|
||||
{
|
||||
|
||||
|
|
@ -116,6 +114,5 @@ inline Int128 multiply128 (uint64_t a, uint64_t b)
|
|||
|
||||
|
||||
} // namespace choc::math
|
||||
} // anonymous namespace
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -65,14 +65,37 @@
|
|||
#pragma GCC diagnostic ignored "-Wnarrowing"
|
||||
#pragma GCC diagnostic ignored "-Wparentheses"
|
||||
#pragma GCC diagnostic ignored "-Wwrite-strings"
|
||||
#pragma GCC diagnostic ignored "-Wformat-overflow"
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-copy-with-dtor"
|
||||
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated"
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#pragma GCC diagnostic ignored "-Wuse-after-free"
|
||||
#pragma GCC diagnostic ignored "-Warray-bounds"
|
||||
#pragma GCC diagnostic ignored "-Wvolatile"
|
||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
|
||||
#ifndef __MINGW32__
|
||||
#pragma GCC diagnostic ignored "-Wredundant-move"
|
||||
#endif
|
||||
#else
|
||||
#pragma warning (push, 0)
|
||||
#pragma warning (disable: 2440)
|
||||
#pragma warning (disable: 2664)
|
||||
#pragma warning (disable: 4244)
|
||||
#pragma warning (disable: 4701)
|
||||
#pragma warning (disable: 4702)
|
||||
#pragma warning (disable: 4706)
|
||||
#pragma warning (disable: 4722)
|
||||
#pragma warning (disable: 6011)
|
||||
#pragma warning (disable: 6246)
|
||||
#pragma warning (disable: 6255)
|
||||
#pragma warning (disable: 6262)
|
||||
#pragma warning (disable: 6297)
|
||||
#pragma warning (disable: 6308)
|
||||
#pragma warning (disable: 6323)
|
||||
#pragma warning (disable: 6340)
|
||||
#pragma warning (disable: 6385)
|
||||
#pragma warning (disable: 6386)
|
||||
#pragma warning (disable: 28182)
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@
|
|||
#include <string>
|
||||
#include "../math/choc_MathHelpers.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace choc::text
|
||||
{
|
||||
|
||||
|
|
@ -395,6 +393,5 @@ inline std::string floatToString (float value, int maxDecimals, bool omitPointIf
|
|||
inline std::string floatToString (double value, int maxDecimals, bool omitPointIfPossible) { return FloatToStringBuffer<double> (value, maxDecimals, omitPointIfPossible).toString(); }
|
||||
|
||||
} // namespace choc::text
|
||||
} // anonymous namespace
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -31,8 +31,6 @@
|
|||
#undef max // It's never a smart idea to include any C headers before your C++ ones, as it
|
||||
#undef min // risks polluting your namespace with all kinds of dangerous macros like these ones.
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace choc::json
|
||||
{
|
||||
|
||||
|
|
@ -48,14 +46,14 @@ struct ParseError : public std::runtime_error
|
|||
|
||||
/// Parses some JSON text into a choc::value::Value object, using the given pool.
|
||||
/// Any errors will result in a ParseError exception being thrown.
|
||||
value::Value parse (text::UTF8Pointer);
|
||||
[[nodiscard]] value::Value parse (text::UTF8Pointer);
|
||||
|
||||
/// Parses some JSON text into a choc::value::Value object, using the given pool.
|
||||
/// Any errors will result in a ParseError exception being thrown.
|
||||
value::Value parse (std::string_view);
|
||||
[[nodiscard]] value::Value parse (std::string_view);
|
||||
|
||||
/// Attempts to parse a bare JSON value such as a number, string, object etc
|
||||
value::Value parseValue (std::string_view);
|
||||
[[nodiscard]] value::Value parseValue (std::string_view);
|
||||
|
||||
/// A helper function to create a JSON-friendly Value object with a set of properties.
|
||||
/// The argument list must be contain pairs of names and values, e.g.
|
||||
|
|
@ -67,13 +65,13 @@ value::Value parseValue (std::string_view);
|
|||
/// Essentially, this is a shorthand for calling choc::value::createObject()
|
||||
/// and passing it an empty type name.
|
||||
template <typename... Properties>
|
||||
value::Value create (Properties&&... propertyNamesAndValues);
|
||||
[[nodiscard]] value::Value create (Properties&&... propertyNamesAndValues);
|
||||
|
||||
//==============================================================================
|
||||
/// Formats a value as a JSON string.
|
||||
/// If useLineBreaks is true, it'll be formatted as multi-line JSON, if false it'll
|
||||
/// just be returned as a single line.
|
||||
std::string toString (const value::ValueView&, bool useLineBreaks = false);
|
||||
[[nodiscard]] std::string toString (const value::ValueView&, bool useLineBreaks = false);
|
||||
|
||||
/// Writes a version of a string to an output stream, with any illegal or non-ascii
|
||||
/// written as their equivalent JSON escape sequences.
|
||||
|
|
@ -82,15 +80,15 @@ void writeWithEscapeCharacters (OutputStreamType&, text::UTF8Pointer sourceStrin
|
|||
|
||||
/// Returns a version of a string with illegal or non-ascii converted into the
|
||||
/// equivalent JSON escape sequences.
|
||||
std::string addEscapeCharacters (text::UTF8Pointer sourceString);
|
||||
[[nodiscard]] std::string addEscapeCharacters (text::UTF8Pointer sourceString);
|
||||
|
||||
/// Returns a version of a string with illegal or non-ascii converted into the
|
||||
/// equivalent JSON escape sequences.
|
||||
std::string addEscapeCharacters (std::string_view sourceString);
|
||||
[[nodiscard]] std::string addEscapeCharacters (std::string_view sourceString);
|
||||
|
||||
/// Returns a version of a string with illegal or non-ascii converted into the
|
||||
/// equivalent JSON escape sequences.
|
||||
std::string getEscapedQuotedString (std::string_view sourceString);
|
||||
[[nodiscard]] std::string getEscapedQuotedString (std::string_view sourceString);
|
||||
|
||||
/// Converts a double to a JSON-format string representation.
|
||||
std::string doubleToString (double value);
|
||||
|
|
@ -160,7 +158,7 @@ void writeWithEscapeCharacters (OutputStreamType& out, text::UTF8Pointer source)
|
|||
|
||||
inline std::string addEscapeCharacters (text::UTF8Pointer source)
|
||||
{
|
||||
std::ostringstream result;
|
||||
std::ostringstream result (std::ios::binary);
|
||||
writeWithEscapeCharacters (result, source);
|
||||
return result.str();
|
||||
}
|
||||
|
|
@ -172,7 +170,7 @@ inline std::string addEscapeCharacters (std::string_view source)
|
|||
|
||||
inline std::string getEscapedQuotedString (std::string_view s)
|
||||
{
|
||||
std::ostringstream result;
|
||||
std::ostringstream result (std::ios::binary);
|
||||
result << '"';
|
||||
writeWithEscapeCharacters (result, text::UTF8Pointer (std::string (s).c_str()));
|
||||
result << '"';
|
||||
|
|
@ -287,7 +285,7 @@ void writeAsJSON (Stream& output, const value::ValueView& value, bool useMultipl
|
|||
|
||||
inline std::string toString (const value::ValueView& v, bool useLineBreaks)
|
||||
{
|
||||
std::ostringstream out;
|
||||
std::ostringstream out (std::ios::binary);
|
||||
writeAsJSON (out, v, useLineBreaks);
|
||||
return out.str();
|
||||
}
|
||||
|
|
@ -458,7 +456,7 @@ inline value::Value parse (text::UTF8Pointer text, bool parseBareValue)
|
|||
|
||||
std::string parseString()
|
||||
{
|
||||
std::ostringstream s;
|
||||
std::ostringstream s (std::ios::binary);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
|
@ -559,6 +557,5 @@ value::Value create (Properties&&... properties)
|
|||
|
||||
|
||||
} // namespace choc::json
|
||||
} // anonymous namespace
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -29,8 +29,6 @@
|
|||
#include <cwctype>
|
||||
#include "../platform/choc_Assert.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace choc::text
|
||||
{
|
||||
|
||||
|
|
@ -42,77 +40,80 @@ inline bool isDigit (char c) { return static_
|
|||
/// The arguments must be a sequence of pairs of strings, where the first of each pair is the string to
|
||||
/// look for, followed by its replacement.
|
||||
template <typename StringType, typename... OtherReplacements>
|
||||
std::string replace (StringType textToSearch,
|
||||
std::string_view firstSubstringToReplace, std::string_view firstReplacement,
|
||||
OtherReplacements&&... otherPairsOfStringsToReplace);
|
||||
[[nodiscard]] std::string replace (StringType textToSearch,
|
||||
std::string_view firstSubstringToReplace, std::string_view firstReplacement,
|
||||
OtherReplacements&&... otherPairsOfStringsToReplace);
|
||||
|
||||
/// Returns a string with any whitespace trimmed from its start and end.
|
||||
std::string trim (std::string textToTrim);
|
||||
[[nodiscard]] std::string trim (std::string textToTrim);
|
||||
|
||||
/// Returns a string with any whitespace trimmed from its start and end.
|
||||
std::string_view trim (std::string_view textToTrim);
|
||||
[[nodiscard]] std::string_view trim (std::string_view textToTrim);
|
||||
|
||||
/// Returns a string with any whitespace trimmed from its start and end.
|
||||
std::string_view trim (const char* textToTrim);
|
||||
[[nodiscard]] std::string_view trim (const char* textToTrim);
|
||||
|
||||
/// Returns a string with any whitespace trimmed from its start.
|
||||
std::string trimStart (std::string textToTrim);
|
||||
[[nodiscard]] std::string trimStart (std::string textToTrim);
|
||||
|
||||
/// Returns a string with any whitespace trimmed from its start.
|
||||
std::string_view trimStart (std::string_view textToTrim);
|
||||
[[nodiscard]] std::string_view trimStart (std::string_view textToTrim);
|
||||
|
||||
/// Returns a string with any whitespace trimmed from its start.
|
||||
std::string_view trimStart (const char* textToTrim);
|
||||
[[nodiscard]] std::string_view trimStart (const char* textToTrim);
|
||||
|
||||
/// Returns a string with any whitespace trimmed from its end.
|
||||
std::string trimEnd (std::string textToTrim);
|
||||
[[nodiscard]] std::string trimEnd (std::string textToTrim);
|
||||
|
||||
/// Returns a string with any whitespace trimmed from its end.
|
||||
std::string_view trimEnd (std::string_view textToTrim);
|
||||
[[nodiscard]] std::string_view trimEnd (std::string_view textToTrim);
|
||||
|
||||
/// Returns a string with any whitespace trimmed from its end.
|
||||
std::string_view trimEnd (const char* textToTrim);
|
||||
[[nodiscard]] std::string_view trimEnd (const char* textToTrim);
|
||||
|
||||
/// If the string begins with one or more instances of the given character, this
|
||||
/// skips past them, returning the remainder of the string.
|
||||
std::string_view trimCharacterAtStart (std::string_view textToTrim, char characterToSkip);
|
||||
[[nodiscard]] std::string_view trimCharacterAtStart (std::string_view textToTrim, char characterToSkip);
|
||||
|
||||
/// If the given character is at the start and end of the string, it trims it away.
|
||||
std::string removeOuterCharacter (std::string text, char outerChar);
|
||||
[[nodiscard]] std::string removeOuterCharacter (std::string text, char outerChar);
|
||||
|
||||
inline std::string removeDoubleQuotes (std::string text) { return removeOuterCharacter (std::move (text), '"'); }
|
||||
inline std::string removeSingleQuotes (std::string text) { return removeOuterCharacter (std::move (text), '\''); }
|
||||
[[nodiscard]] inline std::string removeDoubleQuotes (std::string text) { return removeOuterCharacter (std::move (text), '"'); }
|
||||
[[nodiscard]] inline std::string removeSingleQuotes (std::string text) { return removeOuterCharacter (std::move (text), '\''); }
|
||||
|
||||
inline std::string addDoubleQuotes (std::string text) { return "\"" + std::move (text) + "\""; }
|
||||
inline std::string addSingleQuotes (std::string text) { return "'" + std::move (text) + "'"; }
|
||||
[[nodiscard]] inline std::string addDoubleQuotes (std::string text) { return "\"" + std::move (text) + "\""; }
|
||||
[[nodiscard]] inline std::string addSingleQuotes (std::string text) { return "'" + std::move (text) + "'"; }
|
||||
|
||||
std::string toLowerCase (std::string);
|
||||
std::string toUpperCase (std::string);
|
||||
[[nodiscard]] std::string toLowerCase (std::string);
|
||||
[[nodiscard]] std::string toUpperCase (std::string);
|
||||
|
||||
template <typename IsDelimiterChar>
|
||||
std::vector<std::string> splitString (std::string_view textToSplit,
|
||||
IsDelimiterChar&& isDelimiterChar,
|
||||
bool includeDelimitersInResult);
|
||||
[[nodiscard]] std::vector<std::string> splitString (std::string_view textToSplit,
|
||||
IsDelimiterChar&& isDelimiterChar,
|
||||
bool includeDelimitersInResult);
|
||||
|
||||
template <typename CharStartsDelimiter, typename CharIsInDelimiterBody>
|
||||
std::vector<std::string> splitString (std::string_view textToSplit,
|
||||
CharStartsDelimiter&& isDelimiterStart,
|
||||
CharIsInDelimiterBody&& isDelimiterBody,
|
||||
bool includeDelimitersInResult);
|
||||
[[nodiscard]] std::vector<std::string> splitString (std::string_view textToSplit,
|
||||
CharStartsDelimiter&& isDelimiterStart,
|
||||
CharIsInDelimiterBody&& isDelimiterBody,
|
||||
bool includeDelimitersInResult);
|
||||
|
||||
std::vector<std::string> splitString (std::string_view textToSplit,
|
||||
char delimiterCharacter,
|
||||
bool includeDelimitersInResult);
|
||||
[[nodiscard]] std::vector<std::string> splitString (std::string_view textToSplit,
|
||||
char delimiterCharacter,
|
||||
bool includeDelimitersInResult);
|
||||
|
||||
std::vector<std::string> splitAtWhitespace (std::string_view text, bool keepDelimiters = false);
|
||||
[[nodiscard]] std::vector<std::string> splitAtWhitespace (std::string_view text,
|
||||
bool keepDelimiters = false);
|
||||
|
||||
/// Splits a string at newline characters, returning an array of strings.
|
||||
std::vector<std::string> splitIntoLines (std::string_view text, bool includeNewLinesInResult);
|
||||
[[nodiscard]] std::vector<std::string> splitIntoLines (std::string_view text,
|
||||
bool includeNewLinesInResult);
|
||||
|
||||
/// Joins some kind of array of strings into a single string, adding the given separator
|
||||
/// between them (but not adding it at the start or end)
|
||||
template <typename ArrayOfStrings>
|
||||
std::string joinStrings (const ArrayOfStrings& strings, std::string_view separator);
|
||||
[[nodiscard]] std::string joinStrings (const ArrayOfStrings& strings,
|
||||
std::string_view separator);
|
||||
|
||||
/// Returns true if this text contains the given sub-string.
|
||||
bool contains (std::string_view text, std::string_view possibleSubstring);
|
||||
|
|
@ -595,6 +596,5 @@ inline std::string percentEncodeURI (std::string_view text)
|
|||
|
||||
|
||||
} // namespace choc::text
|
||||
} // anonymous namespace
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -22,8 +22,6 @@
|
|||
#include <cstddef>
|
||||
#include "choc_StringUtilities.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace choc::text
|
||||
{
|
||||
|
||||
|
|
@ -103,14 +101,14 @@ struct UTF8Pointer
|
|||
|
||||
/// Returns a pointer to the first non-whitespace character in the given string (which may
|
||||
/// be the terminating null character if it's all whitespace).
|
||||
UTF8Pointer findEndOfWhitespace() const;
|
||||
[[nodiscard]] UTF8Pointer findEndOfWhitespace() const;
|
||||
|
||||
/// Iterates backwards from this position to find the first character that follows
|
||||
/// a new-line. The pointer provided marks the furthest back that the function should search
|
||||
UTF8Pointer findStartOfLine (UTF8Pointer startOfValidText) const;
|
||||
[[nodiscard]] UTF8Pointer findStartOfLine (UTF8Pointer startOfValidText) const;
|
||||
|
||||
/// Searches forwards for the next character that is followed by a new-line or a null-terminator.
|
||||
UTF8Pointer findEndOfLine() const;
|
||||
[[nodiscard]] UTF8Pointer findEndOfLine() const;
|
||||
|
||||
//==============================================================================
|
||||
struct EndIterator {};
|
||||
|
|
@ -200,7 +198,7 @@ bool isValidCESU8 (std::string_view utf8);
|
|||
|
||||
/// Converts any 32-bit characters in this UTF-8 string to surrogate pairs, which makes
|
||||
/// the resulting string suitable for use at CESU-8.
|
||||
std::string convertUTF8ToCESU8 (UTF8Pointer);
|
||||
[[nodiscard]] std::string convertUTF8ToCESU8 (UTF8Pointer);
|
||||
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -653,6 +651,5 @@ inline std::string convertUTF8ToCESU8 (UTF8Pointer utf8)
|
|||
|
||||
|
||||
} // namespace choc::text
|
||||
} // anonymous namespace
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -32,16 +32,9 @@
|
|||
==============================================================================
|
||||
*/
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-copy-with-dtor",
|
||||
"-Wunused-but-set-variable",
|
||||
"-Wdeprecated",
|
||||
"-Wunused-function",
|
||||
"-Wpedantic")
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4163 6011 6246 6255 6262 6297 6308 6323 6340 6385 6386 28182)
|
||||
#define choc juce::detail::choc
|
||||
#include <juce_core/javascript/choc/javascript/choc_javascript_QuickJS.h>
|
||||
#include <juce_core/javascript/choc/javascript/choc_javascript.h>
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
#undef choc
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
|
@ -56,7 +49,7 @@ template <typename T>
|
|||
static int64_t toJuceInt64 (const T& convertible) { return (int64) (int64_t) convertible; }
|
||||
|
||||
//==============================================================================
|
||||
namespace qjs = choc::javascript::quickjs;
|
||||
namespace qjs = detail::choc::javascript::quickjs;
|
||||
|
||||
using VarOrError = std::variant<var, String>;
|
||||
|
||||
|
|
@ -412,7 +405,7 @@ static VarOrError quickJSToJuce (const qjs::QuickJSContext::ValuePtr& ptr)
|
|||
{
|
||||
return tryQuickJSToJuce (ptr);
|
||||
}
|
||||
catch (const choc::javascript::Error& error)
|
||||
catch (const detail::choc::javascript::Error& error)
|
||||
{
|
||||
return String (error.what());
|
||||
}
|
||||
|
|
@ -428,17 +421,12 @@ class detail::QuickJSWrapper
|
|||
public:
|
||||
qjs::JSContext* getQuickJSContext() const
|
||||
{
|
||||
return static_cast<qjs::QuickJSContext*> (context.getPimpl())->context;
|
||||
return impl->context;
|
||||
}
|
||||
|
||||
qjs::JSRuntime* getQuickJSRuntime() const
|
||||
{
|
||||
return static_cast<qjs::QuickJSContext*> (context.getPimpl())->runtime;
|
||||
}
|
||||
|
||||
choc::javascript::Context& getContext()
|
||||
{
|
||||
return context;
|
||||
return impl->runtime;
|
||||
}
|
||||
|
||||
/* Returning a value > 0 will interrupt the QuickJS engine.
|
||||
|
|
@ -460,7 +448,7 @@ private:
|
|||
return 0;
|
||||
}
|
||||
|
||||
choc::javascript::Context context = choc::javascript::createQuickJSContext();
|
||||
std::unique_ptr<qjs::QuickJSContext> impl = std::make_unique<qjs::QuickJSContext>();
|
||||
std::function<int()> interruptHandler;
|
||||
};
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
|
@ -558,11 +546,11 @@ struct DynamicObjectWrapper
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
static choc::javascript::quickjs::JSValue callDispatcher (qjs::JSContext* ctx,
|
||||
qjs::JSValueConst thisValue,
|
||||
int numArgs,
|
||||
qjs::JSValueConst* args,
|
||||
int ordinal)
|
||||
static qjs::JSValue callDispatcher (qjs::JSContext* ctx,
|
||||
qjs::JSValueConst thisValue,
|
||||
int numArgs,
|
||||
qjs::JSValueConst* args,
|
||||
int ordinal)
|
||||
{
|
||||
auto& self = *static_cast<DynamicObjectWrapper*> (qjs::JS_GetOpaque2 (ctx, thisValue, getClassId()));
|
||||
const auto argList = quickJSToJuce (Span { args, (size_t) numArgs }, ctx);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue