diff --git a/.gitmodules b/.gitmodules index 1d0ff263..4a10627f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,6 @@ [submodule "lib/dtl"] path = lib/dtl url = https://github.com/cubicdaiya/dtl.git +[submodule "lib/ankerl_unordered_dense"] + path = lib/ankerl_unordered_dense + url = https://github.com/martinus/unordered_dense.git diff --git a/CHANGELOG.md b/CHANGELOG.md index 74d974eb..fbc3a11e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,7 @@ - wasm export: we can now run ArkScript code on the web! - `GET_CURRENT_PAGE_ADDRESS` instruction to push the current page address to the stack - `CALL_CURRENT_PAGE` super instruction, calling the current page with a given number of arguments (avoid loading a page address on the stack, then popping it to perform the call) +- new data type `Dict`, which can be created with `(dict "key" "value" ...)`, and manipulated with `dict:get`, `dict:add`, `dict:contains`, `dict:remove`, `dict:keys` and `dict:size` ### Changed - instructions are on 4 bytes: 1 byte for the instruction, 1 byte of padding, 2 bytes for an immediate argument diff --git a/CMakeLists.txt b/CMakeLists.txt index da9ff988..5ddde848 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,17 +2,22 @@ cmake_minimum_required(VERSION 3.16) project(ark CXX) -# VERSION +# ArkScript version (have to manually update it) set(ARK_VERSION_MAJOR 4) set(ARK_VERSION_MINOR 0) set(ARK_VERSION_PATCH 0) -execute_process( - COMMAND git rev-parse --short=8 HEAD - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE GIT_COMMIT_HASH - OUTPUT_STRIP_TRAILING_WHITESPACE) -set(ARK_COMMIT ${GIT_COMMIT_HASH}) +# determine whether this is a standalone project or included by other projects +if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) + execute_process( + COMMAND git rev-parse --short=8 HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_COMMIT_HASH + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(ARK_COMMIT ${GIT_COMMIT_HASH}) +else () + set(ARK_COMMIT "deadbeef") +endif () option(ARK_BUILD_EXE "Build a standalone arkscript executable" Off) option(ARK_ENABLE_SYSTEM "Enable sys:exec" On) # enable use of (sys:exec "command here") @@ -34,65 +39,63 @@ if (NOT ARK_EMSCRIPTEN) include(cmake/sanitizers.cmake) include(GNUInstallDirs) # Uses GNU Install directory variables endif () + include(cmake/CPM.cmake) -# configure installer.iss +##################################################### +# Configure files +##################################################### + +## installer.iss configure_file( ${ark_SOURCE_DIR}/Installer.iss.in ${ark_SOURCE_DIR}/Installer.iss) -# setting up compilations options +## Ark/Constants.hpp +message(STATUS "ArkScript version ${ARK_VERSION_MAJOR}.${ARK_VERSION_MINOR}.${ARK_VERSION_PATCH}-${ARK_COMMIT}") +configure_file( + ${ark_SOURCE_DIR}/include/Ark/Constants.hpp.in + ${ark_SOURCE_DIR}/include/Ark/Constants.hpp) + +##################################################### +# Compilations options and project declaration +##################################################### + +set(CMAKE_POSITION_INDEPENDENT_CODE ON) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") set(CMAKE_COMPILER_IS_CLANG ON) endif () -set(CMAKE_POSITION_INDEPENDENT_CODE ON) - -# files needed for the library ArkReactor file(GLOB_RECURSE SOURCE_FILES ${ark_SOURCE_DIR}/src/arkreactor/*.cpp ${ark_SOURCE_DIR}/lib/fmt/src/format.cc) add_library(ArkReactor SHARED ${SOURCE_FILES}) + if (NOT ARK_EMSCRIPTEN) enable_lto(ArkReactor) endif () + target_include_directories(ArkReactor PUBLIC ${ark_SOURCE_DIR}/include) +target_include_directories(ArkReactor + SYSTEM PUBLIC + "${ark_SOURCE_DIR}/lib/picosha2/" + "${ark_SOURCE_DIR}/lib/fmt/include") + target_compile_features(ArkReactor PRIVATE cxx_std_20) +if (ARK_ENABLE_SYSTEM) + target_compile_definitions(ArkReactor PRIVATE ARK_ENABLE_SYSTEM) +endif () + if (ARK_UNITY_BUILD) set_target_properties(ArkReactor PROPERTIES UNITY_BUILD ON UNITY_BUILD_MODE BATCH UNITY_BUILD_BATCH_SIZE 16) set_source_files_properties(src/arkreactor/VM/VM.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION true) endif () -if (ARK_EMSCRIPTEN) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/public") - - # ArkScript lib needs to know if we are building an exe to enable/disable specific code for embedding - target_compile_definitions(ArkReactor PRIVATE ARK_BUILD_EXE=1) - - add_executable(ArkEmscripten ${ark_SOURCE_DIR}/src/arkemscripten/main.cpp) - target_link_libraries(ArkEmscripten PUBLIC ArkReactor) - target_compile_features(ArkEmscripten PRIVATE cxx_std_20) - - # enable_lto(ArkEmscripten) - - if (ARK_JS_ONLY) - message(STATUS "Setting compilation target to native JavaScript") - set(CMAKE_EXECUTABLE_SUFFIX ".js") - set_target_properties(ArkReactor PROPERTIES LINK_FLAGS "-s WASM=0 -s NO_DISABLE_EXCEPTION_CATCHING") - set_target_properties(ArkEmscripten PROPERTIES LINK_FLAGS "-s WASM=0 -s NO_DISABLE_EXCEPTION_CATCHING -s EXPORTED_FUNCTIONS='[_main]' -s EXPORTED_RUNTIME_METHODS=['run'] -lembind") - else () - message(STATUS "Setting compilation target to WASM") - set(CMAKE_EXECUTABLE_SUFFIX ".wasm.js") - set_target_properties(ArkReactor PROPERTIES LINK_FLAGS "-s WASM=1 -s NO_DISABLE_EXCEPTION_CATCHING") - set_target_properties(ArkEmscripten PROPERTIES LINK_FLAGS "-s WASM=1 -s NO_DISABLE_EXCEPTION_CATCHING -s EXPORTED_FUNCTIONS='[_main]' -s EXPORTED_RUNTIME_METHODS=['run'] -lembind") - endif () -endif () - if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG OR APPLE) message(STATUS "Enabling computed gotos") target_compile_definitions(ArkReactor PRIVATE ARK_USE_COMPUTED_GOTOS=1) @@ -155,25 +158,22 @@ elseif (MSVC) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:8000000") # set stack size to 8MB endif () +##################################################### # Link libraries +##################################################### -target_include_directories(ArkReactor - SYSTEM PUBLIC - "${ark_SOURCE_DIR}/lib/picosha2/" - "${ark_SOURCE_DIR}/lib/fmt/include") +add_subdirectory("${ark_SOURCE_DIR}/lib/ankerl_unordered_dense" EXCLUDE_FROM_ALL) +target_link_libraries(ArkReactor PUBLIC unordered_dense::unordered_dense) if (UNIX OR LINUX) find_package(Threads) target_link_libraries(ArkReactor PRIVATE ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT}) endif () -# configuring Constants.hpp -message(STATUS "ArkScript version ${ARK_VERSION_MAJOR}.${ARK_VERSION_MINOR}.${ARK_VERSION_PATCH}-${ARK_COMMIT}") -configure_file( - ${ark_SOURCE_DIR}/include/Ark/Constants.hpp.in - ${ark_SOURCE_DIR}/include/Ark/Constants.hpp) - +##################################################### # Installation rules +##################################################### + if (NOT ARK_EMSCRIPTEN) # Installs the dynamic library file. install(TARGETS ArkReactor @@ -193,13 +193,11 @@ if (NOT ARK_EMSCRIPTEN) endif () endif () -# COMPILATION RELATED - target_compile_definitions(ArkReactor PRIVATE ARK_EXPORT) -if (ARK_ENABLE_SYSTEM) - target_compile_definitions(ArkReactor PRIVATE ARK_ENABLE_SYSTEM) -endif () +##################################################### +# Create the different (optional) targets +##################################################### if (ARK_BUILD_MODULES) get_directory_property(old_dir_compile_options COMPILE_OPTIONS) @@ -213,6 +211,29 @@ if (ARK_TESTS OR ARK_BUILD_EXE) add_subdirectory("${ark_SOURCE_DIR}/lib/clipp" EXCLUDE_FROM_ALL) endif () +if (ARK_EMSCRIPTEN) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/public") + + # ArkScript lib needs to know if we are building an exe to enable/disable specific code for embedding + target_compile_definitions(ArkReactor PRIVATE ARK_BUILD_EXE=1) + + add_executable(ArkEmscripten ${ark_SOURCE_DIR}/src/arkemscripten/main.cpp) + target_link_libraries(ArkEmscripten PUBLIC ArkReactor) + target_compile_features(ArkEmscripten PRIVATE cxx_std_20) + + if (ARK_JS_ONLY) + message(STATUS "Setting compilation target to native JavaScript") + set(CMAKE_EXECUTABLE_SUFFIX ".js") + set_target_properties(ArkReactor PROPERTIES LINK_FLAGS "-s WASM=0 -s NO_DISABLE_EXCEPTION_CATCHING") + set_target_properties(ArkEmscripten PROPERTIES LINK_FLAGS "-s WASM=0 -s NO_DISABLE_EXCEPTION_CATCHING -s EXPORTED_FUNCTIONS='[_main]' -s EXPORTED_RUNTIME_METHODS=['run'] -lembind") + else () + message(STATUS "Setting compilation target to WASM") + set(CMAKE_EXECUTABLE_SUFFIX ".wasm.js") + set_target_properties(ArkReactor PROPERTIES LINK_FLAGS "-s WASM=1 -s NO_DISABLE_EXCEPTION_CATCHING") + set_target_properties(ArkEmscripten PROPERTIES LINK_FLAGS "-s WASM=1 -s NO_DISABLE_EXCEPTION_CATCHING -s EXPORTED_FUNCTIONS='[_main]' -s EXPORTED_RUNTIME_METHODS=['run'] -lembind") + endif () +endif () + if (ARK_TESTS) file(GLOB_RECURSE SOURCES ${ark_SOURCE_DIR}/tests/unittests/*.cpp diff --git a/include/Ark/Builtins/Builtins.hpp b/include/Ark/Builtins/Builtins.hpp index 5531f288..72ab744a 100644 --- a/include/Ark/Builtins/Builtins.hpp +++ b/include/Ark/Builtins/Builtins.hpp @@ -14,13 +14,14 @@ #include #include -#include namespace Ark { class VM; } +#define ARK_BUILTIN(name) Value name(std::vector& n, VM* vm) + namespace Ark::internal::Builtins { extern const Value falseSym; @@ -35,60 +36,60 @@ namespace Ark::internal::Builtins // ------------------------------ namespace List { - Value reverseList(std::vector& n, VM* vm); // builtin__list:reverse, single arg - Value findInList(std::vector& n, VM* vm); // builtin__list:find, 2 arguments - Value sliceList(std::vector& n, VM* vm); // builtin__list:slice, 4 arguments - Value sort_(std::vector& n, VM* vm); // builtin__list:sort, 1 argument - Value fill(std::vector& n, VM* vm); // builtin__list:fill, 2 arguments - Value setListAt(std::vector& n, VM* vm); // builtin__list:setAt, 3 arguments + ARK_BUILTIN(reverseList); + ARK_BUILTIN(findInList); + ARK_BUILTIN(sliceList); + ARK_BUILTIN(sort_); + ARK_BUILTIN(fill); + ARK_BUILTIN(setListAt); } namespace IO { - Value print(std::vector& n, VM* vm); // print, multiple arguments - Value puts_(std::vector& n, VM* vm); // puts, multiple arguments - Value input(std::vector& n, VM* vm); // input, 0 or 1 argument - Value writeFile(std::vector& n, VM* vm); // builtin__io:writeFile, 2 arguments - Value appendToFile(std::vector& n, VM* vm); // builtin__io:appendToFile, 2 arguments - Value readFile(std::vector& n, VM* vm); // builtin__io:readFile, 1 argument - Value fileExists(std::vector& n, VM* vm); // builtin__io:fileExists?, 1 argument - Value listFiles(std::vector& n, VM* vm); // builtin__io:listFiles, 1 argument - Value isDirectory(std::vector& n, VM* vm); // builtin__io:isDir?, 1 argument - Value makeDir(std::vector& n, VM* vm); // builtin__io:makeDir, 1 argument - Value removeFile(std::vector& n, VM* vm); // builtin__io:removeFile, multiple arguments + ARK_BUILTIN(print); + ARK_BUILTIN(puts_); + ARK_BUILTIN(input); + ARK_BUILTIN(writeFile); + ARK_BUILTIN(appendToFile); + ARK_BUILTIN(readFile); + ARK_BUILTIN(fileExists); + ARK_BUILTIN(listFiles); + ARK_BUILTIN(isDirectory); + ARK_BUILTIN(makeDir); + ARK_BUILTIN(removeFile); } namespace Time { - Value timeSinceEpoch(std::vector& n, VM* vm); // time, 0 argument + ARK_BUILTIN(timeSinceEpoch); } namespace System { - Value system_(std::vector& n, VM* vm); // builtin__sys:exec, 1 argument - Value sleep(std::vector& n, VM* vm); // builtin__sys:sleep, 1 argument - Value exit_(std::vector& n, VM* vm); // builtin__sys:exit, 1 argument + ARK_BUILTIN(system_); + ARK_BUILTIN(sleep); + ARK_BUILTIN(exit_); } namespace String { - Value format(std::vector& n, VM* vm); // format, multiple arguments - Value findSubStr(std::vector& n, VM* vm); // builtin__string:find, 2 arguments - Value removeAtStr(std::vector& n, VM* vm); // builtin__string:removeAt, 2 arguments - Value ord(std::vector& n, VM* vm); // builtin__string:ord, 1 arguments - Value chr(std::vector& n, VM* vm); // builtin__string:chr, 1 arguments - Value setStringAt(std::vector& n, VM* vm); // builtin__string::setAt, 3 arguments + ARK_BUILTIN(format); + ARK_BUILTIN(findSubStr); + ARK_BUILTIN(removeAtStr); + ARK_BUILTIN(ord); + ARK_BUILTIN(chr); + ARK_BUILTIN(setStringAt); } namespace Mathematics { - Value exponential(std::vector& n, VM* vm); // builtin__math:exp, 1 argument - Value logarithm(std::vector& n, VM* vm); // builtin__math:ln, 1 argument - Value ceil_(std::vector& n, VM* vm); // builtin__math:ceil, 1 argument - Value floor_(std::vector& n, VM* vm); // builtin__math:floor, 1 argument - Value round_(std::vector& n, VM* vm); // builtin__math:round, 1 argument - Value isnan_(std::vector& n, VM* vm); // builtin__math:NaN?, 1 argument - Value isinf_(std::vector& n, VM* vm); // builtin__math:Inf?, 1 argument + ARK_BUILTIN(exponential); + ARK_BUILTIN(logarithm); + ARK_BUILTIN(ceil_); + ARK_BUILTIN(floor_); + ARK_BUILTIN(round_); + ARK_BUILTIN(isnan_); + ARK_BUILTIN(isinf_); extern const Value pi_; extern const Value e_; @@ -96,27 +97,40 @@ namespace Ark::internal::Builtins extern const Value inf_; extern const Value nan_; - Value cos_(std::vector& n, VM* vm); // builtin__math:cos, 1 argument - Value sin_(std::vector& n, VM* vm); // builtin__math:sin, 1 argument - Value tan_(std::vector& n, VM* vm); // builtin__math:tan, 1 argument - Value acos_(std::vector& n, VM* vm); // builtin__math:arccos, 1 argument - Value asin_(std::vector& n, VM* vm); // builtin__math:arcsin, 1 argument - Value atan_(std::vector& n, VM* vm); // builtin__math:arctan, 1 argument - Value cosh_(std::vector& n, VM* vm); // builtin__math:cosh, 1 argument - Value sinh_(std::vector& n, VM* vm); // builtin__math:sinh, 1 argument - Value tanh_(std::vector& n, VM* vm); // builtin__math:tanh, 1 argument - Value acosh_(std::vector& n, VM* vm); // builtin__math:acosh, 1 argument - Value asinh_(std::vector& n, VM* vm); // builtin__math:asinh, 1 argument - Value atanh_(std::vector& n, VM* vm); // builtin__math:atanh, 1 argument - - Value random(std::vector& n, VM* vm); // random, 0-2 args + ARK_BUILTIN(cos_); + ARK_BUILTIN(sin_); + ARK_BUILTIN(tan_); + ARK_BUILTIN(acos_); + ARK_BUILTIN(asin_); + ARK_BUILTIN(atan_); + ARK_BUILTIN(cosh_); + ARK_BUILTIN(sinh_); + ARK_BUILTIN(tanh_); + ARK_BUILTIN(acosh_); + ARK_BUILTIN(asinh_); + ARK_BUILTIN(atanh_); + + ARK_BUILTIN(random); } namespace Async { - Value async(std::vector& n, VM* vm); // async, 1+ arguments - Value await(std::vector& n, VM* vm); // await, 1 argument + ARK_BUILTIN(async); + ARK_BUILTIN(await); + } + + namespace Dict + { + ARK_BUILTIN(dict); + ARK_BUILTIN(get); + ARK_BUILTIN(add); + ARK_BUILTIN(contains); + ARK_BUILTIN(remove); + ARK_BUILTIN(keys); + ARK_BUILTIN(size); } } +#undef ARK_BUILTIN + #endif diff --git a/include/Ark/VM/VM.hpp b/include/Ark/VM/VM.hpp index ece4e432..e04b150c 100644 --- a/include/Ark/VM/VM.hpp +++ b/include/Ark/VM/VM.hpp @@ -389,6 +389,8 @@ namespace Ark #include "VM.inl" + // todo: move to a separate file + /// ArkScript Nil value const auto Nil = Value(ValueType::Nil); /// ArkScript False value diff --git a/include/Ark/VM/VM.inl b/include/Ark/VM/VM.inl index 71bd16f2..3bb5a3e1 100644 --- a/include/Ark/VM/VM.inl +++ b/include/Ark/VM/VM.inl @@ -36,7 +36,7 @@ Value VM::call(const std::string& name, Args&&... args) assert(var != nullptr && "Couldn't find variable"); if (!var->isFunction()) - throwVMError(ErrorKind::Type, fmt::format("Can't call '{}': it isn't a Function but a {}", name, types_to_str[static_cast(var->valueType())])); + throwVMError(ErrorKind::Type, fmt::format("Can't call '{}': it isn't a Function but a {}", name, std::to_string(var->valueType()))); push(Value(var), context); context.last_symbol = id; @@ -60,7 +60,7 @@ Value VM::call(const std::string& name, Args&&... args) inline Value VM::resolve(internal::ExecutionContext* context, const std::vector& n) { if (!n[0].isFunction()) - throw TypeError(fmt::format("VM::resolve couldn't resolve a non-function ({})", types_to_str[static_cast(n[0].valueType())])); + throw TypeError(fmt::format("VM::resolve couldn't resolve a non-function ({})", std::to_string(n[0].valueType()))); const std::size_t ip = context->ip; const std::size_t pp = context->pp; @@ -308,7 +308,7 @@ inline void VM::call(internal::ExecutionContext& context, const uint16_t argc, V ErrorKind::Type, fmt::format( "{} is not a Function but a {}", - maybe_value_ptr->toString(*this), types_to_str[static_cast(call_type)])); + maybe_value_ptr->toString(*this), std::to_string(call_type))); } } diff --git a/include/Ark/VM/Value.hpp b/include/Ark/VM/Value.hpp index af530974..67de6e65 100644 --- a/include/Ark/VM/Value.hpp +++ b/include/Ark/VM/Value.hpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -24,12 +26,9 @@ namespace Ark { - class VM; - class BytecodeReader; - // Order is important because we are doing some optimizations to check ranges // of types based on their integer values. - enum class ValueType + enum class ValueType : unsigned { List = 0, Number = 1, @@ -38,15 +37,16 @@ namespace Ark CProc = 4, Closure = 5, User = 6, + Dict = 7, - Nil = 7, - True = 8, - False = 9, - Undefined = 10, - Reference = 11, - InstPtr = 12, + Nil = 8, + True = 9, + False = 10, + Undefined = 11, + Reference = 12, + InstPtr = 13, - Any = 99 ///< Used only for typechecking + Any = 14 ///< Used only for typechecking }; constexpr std::array types_to_str = { @@ -57,6 +57,7 @@ namespace Ark "CProc", "Closure", "UserType", + "Dict", "Nil", "Bool", "Bool", @@ -65,22 +66,47 @@ namespace Ark "InstPtr", "Any" }; +} + +template <> +struct std::hash +{ + [[nodiscard]] std::size_t operator()(const Ark::ValueType& s) const noexcept + { + return std::hash> {}(static_cast>(s)); + } +}; + +namespace Ark +{ + class VM; + class BytecodeReader; + + namespace internal + { + class Dict; + } class ARK_API Value { public: - using Iterator = std::vector::iterator; + using Number_t = double; + using String_t = std::string; + using List_t = std::vector; + using Ref_t = Value*; + using Dict_t = internal::Dict; using Value_t = std::variant< - double, // 8 bytes - std::string, // 32 bytes - internal::PageAddr_t, // 2 bytes - Procedure, // 32 bytes - internal::Closure, // 24 bytes - UserType, // 24 bytes - std::vector, // 24 bytes - Value* // 8 bytes - >; // +8 bytes overhead + Number_t, // 8 bytes + String_t, // 32 bytes + internal::PageAddr_t, // 2 bytes + Procedure, // 32 bytes + internal::Closure, // 24 bytes + UserType, // 24 bytes + List_t, // 24 bytes + std::shared_ptr, // 32 bytes + Ref_t // 8 bytes + >; // +8 bytes overhead // total 40 bytes /** @@ -112,14 +138,15 @@ namespace Ark explicit Value(int value) noexcept; explicit Value(double value) noexcept; - explicit Value(const std::string& value) noexcept; + explicit Value(const String_t& value) noexcept; explicit Value(const char* value) noexcept; explicit Value(internal::PageAddr_t value) noexcept; explicit Value(Procedure&& value) noexcept; - explicit Value(std::vector&& value) noexcept; + explicit Value(List_t&& value) noexcept; explicit Value(internal::Closure&& value) noexcept; explicit Value(UserType&& value) noexcept; - explicit Value(Value* ref) noexcept; + explicit Value(Dict_t&& value) noexcept; + explicit Value(Ref_t ref) noexcept; [[nodiscard]] ValueType valueType() const noexcept { return m_type; } [[nodiscard]] bool isFunction() const noexcept @@ -132,14 +159,22 @@ namespace Ark return m_type == ValueType::List || m_type == ValueType::String; } - [[nodiscard]] double number() const { return std::get(m_value); } - [[nodiscard]] const std::string& string() const { return std::get(m_value); } - [[nodiscard]] const std::vector& constList() const { return std::get>(m_value); } + [[nodiscard]] Number_t number() const { return std::get(m_value); } + + [[nodiscard]] const String_t& string() const { return std::get(m_value); } + [[nodiscard]] String_t& stringRef() { return std::get(m_value); } + + + [[nodiscard]] const List_t& constList() const { return std::get(m_value); } + [[nodiscard]] List_t& list() { return std::get(m_value); } + [[nodiscard]] const UserType& usertype() const { return std::get(m_value); } - [[nodiscard]] std::vector& list() { return std::get>(m_value); } - [[nodiscard]] std::string& stringRef() { return std::get(m_value); } [[nodiscard]] UserType& usertypeRef() { return std::get(m_value); } - [[nodiscard]] Value* reference() const { return std::get(m_value); } + + [[nodiscard]] const Dict_t& dict() const { return *std::get>(m_value); } + [[nodiscard]] Dict_t& dictRef() { return *std::get>(m_value); } + + [[nodiscard]] Ref_t reference() const { return std::get(m_value); } /** * @brief Add an element to the list held by the value (if the value type is set to list) @@ -163,6 +198,7 @@ namespace Ark friend class Ark::VM; friend class Ark::BytecodeReader; + friend struct std::hash; private: ValueType m_type; @@ -221,12 +257,47 @@ namespace Ark return true; case ValueType::True: - return false; - + [[fallthrough]]; default: return false; } } } +namespace std +{ + [[nodiscard]] inline std::string to_string(const Ark::ValueType type) noexcept + { + const auto index = static_cast>(type); + return Ark::types_to_str[index]; + } +} + +template <> +struct std::hash> +{ + [[nodiscard]] std::size_t operator()(const std::vector& s) const noexcept + { + return std::hash {}(s.data()); + } +}; + +template <> +struct std::hash> +{ + [[nodiscard]] std::size_t operator()(const std::shared_ptr& s) const noexcept + { + return std::hash {}(s.get()); + } +}; + +template <> +struct std::hash +{ + [[nodiscard]] std::size_t operator()(const Ark::Value& s) const noexcept + { + return std::hash {}(s.m_value); + } +}; + #endif diff --git a/include/Ark/VM/Value/Closure.hpp b/include/Ark/VM/Value/Closure.hpp index b067a012..74febc98 100644 --- a/include/Ark/VM/Value/Closure.hpp +++ b/include/Ark/VM/Value/Closure.hpp @@ -12,7 +12,6 @@ #define VM_VALUE_CLOSURE_HPP #include -#include #include #include @@ -78,6 +77,7 @@ namespace Ark::internal friend ARK_API bool operator==(const Closure& A, const Closure& B) noexcept; friend ARK_API_INLINE bool operator<(const Closure& A, const Closure& B) noexcept; + friend struct std::hash; private: std::shared_ptr m_scope; @@ -91,4 +91,13 @@ namespace Ark::internal } } +template <> +struct std::hash +{ + [[nodiscard]] std::size_t operator()(const Ark::internal::Closure& s) const noexcept + { + return std::hash {}(s.m_scope.get()); + } +}; + #endif diff --git a/include/Ark/VM/Value/Dict.hpp b/include/Ark/VM/Value/Dict.hpp new file mode 100644 index 00000000..481d11d0 --- /dev/null +++ b/include/Ark/VM/Value/Dict.hpp @@ -0,0 +1,92 @@ +/** + * @file Dict.hpp + * @author Lex Plateau (lexplt.dev@gmail.com) + * @brief Define how dictionaries are handled + * @date 2025-08-03 + * + * @copyright Copyright (c) 2025 + * + */ + +#ifndef ARK_VM_VALUE_DICT_HPP +#define ARK_VM_VALUE_DICT_HPP + +#include +#include + +#include + +#include + +namespace Ark +{ + class VM; +} + +namespace Ark::internal +{ + class ARK_API Dict + { + public: + Dict() = default; + + /** + * @brief Assign a key to a value inside the dict + * + * @param key + * @param value + */ + void set(const Value& key, const Value& value); + + /** + * @brief Try to get a value from a given key. If no value is found, return Nil + * + * @param key + * @return const Value& + */ + const Value& get(const Value& key); + + /** + * @brief Check that a key exists + * + * @param key + * @return true if the dict has the key + * @return false otherwise + */ + [[nodiscard]] bool contains(const Value& key) const; + + /** + * @brief Remove an entry from the dict via its key + * + * @param key + */ + void remove(const Value& key); + + /** + * @brief Get a list of the dict keys + * + * @return std::vector + */ + std::vector keys(); + + /** + * @brief Compute the number of (key, value) pairs in the dict + * + * @return std::size_t + */ + [[nodiscard]] std::size_t size() const; + + /** + * @brief Convert the dictionary to a string for pretty printing + * + * @param vm + * @return std::string + */ + std::string toString(VM& vm) const; + + private: + ankerl::unordered_dense::map m_dict; + }; +} + +#endif // ARK_VM_VALUE_DICT_HPP diff --git a/include/Ark/VM/Value/Procedure.hpp b/include/Ark/VM/Value/Procedure.hpp index cfd3e00c..f36ec04e 100644 --- a/include/Ark/VM/Value/Procedure.hpp +++ b/include/Ark/VM/Value/Procedure.hpp @@ -40,24 +40,35 @@ namespace Ark * @brief Create a new procedure. */ template + // cppcheck-suppress noExplicitConstructor ; we explicitly want implicit conversion to Procedure Procedure(T&& cb) : m_procedure(cb) - { - } + {} /** * @brief Create a new procedure from a stateless C function pointer. */ - Procedure(PointerType c_ptr); + Procedure(PointerType c_ptr); // cppcheck-suppress noExplicitConstructor ; we explicitly want implicit conversion to Procedure Value operator()(std::vector&, VM*) const; bool operator<(const Procedure& other) const noexcept; bool operator==(const Procedure& other) const noexcept; + friend struct std::hash; + private: CallbackType m_procedure; }; } +template <> +struct std::hash +{ + [[nodiscard]] std::size_t operator()(const Ark::Procedure& s) const noexcept + { + return std::hash {}(static_cast(&s.m_procedure)); + } +}; + #endif diff --git a/include/Ark/VM/Value/UserType.hpp b/include/Ark/VM/Value/UserType.hpp index 47f78af3..fc9c7962 100644 --- a/include/Ark/VM/Value/UserType.hpp +++ b/include/Ark/VM/Value/UserType.hpp @@ -8,8 +8,8 @@ * */ -#ifndef VM_VALUE_USERTYPE_HPP -#define VM_VALUE_USERTYPE_HPP +#ifndef ARK_VM_VALUE_USERTYPE_HPP +#define ARK_VM_VALUE_USERTYPE_HPP #include #include @@ -135,13 +135,22 @@ namespace Ark friend ARK_API bool operator==(const UserType& A, const UserType& B) noexcept; friend ARK_API bool operator<(const UserType& A, const UserType& B) noexcept; friend ARK_API std::ostream& operator<<(std::ostream& os, const UserType& A) noexcept; + friend struct std::hash; private: uint16_t m_type_id; void* m_data; ControlFuncs* m_funcs; }; - } +template <> +struct std::hash +{ + [[nodiscard]] std::size_t operator()(const Ark::UserType& s) const noexcept + { + return std::hash {}(s.m_data); + } +}; + #endif diff --git a/lib/README.md b/lib/README.md index 4b6d1b9e..d5b7ec04 100644 --- a/lib/README.md +++ b/lib/README.md @@ -1,7 +1,8 @@ -# ArkScript thirdparties +# ArkScript third parties Includes +* [ankerl_unordered_dense](https://github.com/martinus/unordered_dense), MIT License * [clipp](https://github.com/SuperFola/clipp), MIT License * [dtl](https://github.com/cubicdaiya/dtl/), BSD License * [fmt](https://github.com/fmtlib/fmt), MIT License diff --git a/lib/ankerl_unordered_dense b/lib/ankerl_unordered_dense new file mode 160000 index 00000000..73f3cbb2 --- /dev/null +++ b/lib/ankerl_unordered_dense @@ -0,0 +1 @@ +Subproject commit 73f3cbb237e84d483afafc743f1f14ec53e12314 diff --git a/lib/std b/lib/std index 68a23dab..c13f009a 160000 --- a/lib/std +++ b/lib/std @@ -1 +1 @@ -Subproject commit 68a23dab6c53b168037c5efff0afa4f387a8a73e +Subproject commit c13f009a485224876b8e20b8d9dcf9c606b3f407 diff --git a/src/arkreactor/Builtins/Builtins.cpp b/src/arkreactor/Builtins/Builtins.cpp index ede239fe..60e5624a 100644 --- a/src/arkreactor/Builtins/Builtins.cpp +++ b/src/arkreactor/Builtins/Builtins.cpp @@ -94,6 +94,15 @@ namespace Ark::internal::Builtins // Async { "async", Value(Async::async) }, - { "await", Value(Async::await) } + { "await", Value(Async::await) }, + + // Dict + { "dict", Value(Dict::dict) }, + { "builtin__dict:get", Value(Dict::get) }, + { "builtin__dict:add", Value(Dict::add) }, + { "builtin__dict:contains", Value(Dict::contains) }, + { "builtin__dict:remove", Value(Dict::remove) }, + { "builtin__dict:keys", Value(Dict::keys) }, + { "builtin__dict:size", Value(Dict::size) } }; } diff --git a/src/arkreactor/Builtins/Dict.cpp b/src/arkreactor/Builtins/Dict.cpp new file mode 100644 index 00000000..59b97a6b --- /dev/null +++ b/src/arkreactor/Builtins/Dict.cpp @@ -0,0 +1,107 @@ +#include +#include + +#include + +#include + +namespace Ark::internal::Builtins::Dict +{ + /** + * @name dict + * @brief Creates a dictionary from a set of arguments, grouping them 2 by 2 to create (key, value) pairs + * @param args... the arguments of the function + * =begin + * (let d (dict "key" "value" 5 12)) + * (print d) # {key: value, 5: 12} + * =end + * @author https://github.com/SuperFola + */ + Value dict(std::vector& n, VM* vm [[maybe_unused]]) + { + if (n.size() % 2 != 0) + throw std::runtime_error( + fmt::format("dict: require an even number of argument to construct (key, value) pairs and create a dictionary. Got {} argument{}", + n.size(), + n.size() > 1 ? "s" : "")); + + internal::Dict dict; + for (std::size_t i = 0, end = n.size(); i < end; i += 2) + dict.set(n[i], n[i + 1]); + + return Value(std::move(dict)); + } + + Value get(std::vector& n, VM* vm [[maybe_unused]]) + { + if (!types::check(n, ValueType::Dict, ValueType::Any)) + throw types::TypeCheckingError( + "dict:get", + { { types::Contract { { types::Typedef("dictionary", ValueType::Dict), + types::Typedef("key", ValueType::Any) } } } }, + n); + + return n[0].dictRef().get(n[1]); + } + + Value add(std::vector& n, VM* vm [[maybe_unused]]) + { + if (!types::check(n, ValueType::Dict, ValueType::Any, ValueType::Any)) + throw types::TypeCheckingError( + "dict:add", + { { types::Contract { { types::Typedef("dictionary", ValueType::Dict), + types::Typedef("key", ValueType::Any), + types::Typedef("value", ValueType::Any) } } } }, + n); + + n[0].dictRef().set(n[1], n[2]); + return Nil; + } + + Value contains(std::vector& n, VM* vm [[maybe_unused]]) + { + if (!types::check(n, ValueType::Dict, ValueType::Any)) + throw types::TypeCheckingError( + "dict:contains", + { { types::Contract { { types::Typedef("dictionary", ValueType::Dict), + types::Typedef("key", ValueType::Any) } } } }, + n); + + return n[0].dictRef().contains(n[1]) ? True : False; + } + + Value remove(std::vector& n, VM* vm [[maybe_unused]]) + { + if (!types::check(n, ValueType::Dict, ValueType::Any)) + throw types::TypeCheckingError( + "dict:remove", + { { types::Contract { { types::Typedef("dictionary", ValueType::Dict), + types::Typedef("key", ValueType::Any) } } } }, + n); + + n[0].dictRef().remove(n[1]); + return Nil; + } + + Value keys(std::vector& n, VM* vm [[maybe_unused]]) + { + if (!types::check(n, ValueType::Dict)) + throw types::TypeCheckingError( + "dict:keys", + { { types::Contract { { types::Typedef("dictionary", ValueType::Dict) } } } }, + n); + + return Value(n[0].dictRef().keys()); + } + + Value size(std::vector& n, VM* vm [[maybe_unused]]) + { + if (!types::check(n, ValueType::Dict)) + throw types::TypeCheckingError( + "dict:size", + { { types::Contract { { types::Typedef("dictionary", ValueType::Dict) } } } }, + n); + + return Value(static_cast(n[0].dictRef().size())); + } +} diff --git a/src/arkreactor/Builtins/List.cpp b/src/arkreactor/Builtins/List.cpp index 36e232af..15ea7dc2 100644 --- a/src/arkreactor/Builtins/List.cpp +++ b/src/arkreactor/Builtins/List.cpp @@ -5,7 +5,6 @@ #include #include -#include namespace Ark::internal::Builtins::List { @@ -17,7 +16,7 @@ namespace Ark::internal::Builtins::List { { types::Contract { { types::Typedef("list", ValueType::List) } } } }, n); - std::reverse(n[0].list().begin(), n[0].list().end()); + std::ranges::reverse(n[0].list()); return n[0]; } @@ -30,7 +29,7 @@ namespace Ark::internal::Builtins::List n); if (const auto it = std::ranges::find(n[0].list(), n[1]); it != n[0].list().end()) - return Value(static_cast(std::distance(n[0].list().begin(), it))); + return Value(static_cast(std::distance(n[0].list().begin(), it))); return Value(-1); } @@ -45,7 +44,7 @@ namespace Ark::internal::Builtins::List types::Typedef("step", ValueType::Number) } } } }, n); - long step = static_cast(n[3].number()); + const long step = static_cast(n[3].number()); if (step <= 0) throw std::runtime_error("list:slice: step can not be null or negative"); @@ -87,8 +86,9 @@ namespace Ark::internal::Builtins::List types::Typedef("value", ValueType::Any) } } } }, n); - auto c = static_cast(n[0].number()); + const auto c = static_cast(n[0].number()); std::vector l; + l.reserve(c); for (std::size_t i = 0; i < c; i++) l.push_back(n[1]); diff --git a/src/arkreactor/Compiler/BytecodeReader.cpp b/src/arkreactor/Compiler/BytecodeReader.cpp index 3f07dcf6..29fe413c 100644 --- a/src/arkreactor/Compiler/BytecodeReader.cpp +++ b/src/arkreactor/Compiler/BytecodeReader.cpp @@ -371,7 +371,7 @@ namespace Ark fmt::println("{}) (PageAddr) {}", j, val.pageAddr()); break; default: - fmt::print(fmt::fg(fmt::color::red), "Value type not handled: {}\n", types_to_str[static_cast(val.valueType())]); + fmt::print(fmt::fg(fmt::color::red), "Value type not handled: {}\n", std::to_string(val.valueType())); break; } } diff --git a/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp b/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp index ac65e946..cc42064d 100644 --- a/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp +++ b/src/arkreactor/Compiler/Lowerer/ASTLowerer.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include diff --git a/src/arkreactor/TypeChecker.cpp b/src/arkreactor/TypeChecker.cpp index 1d6b5ce5..d13b3199 100644 --- a/src/arkreactor/TypeChecker.cpp +++ b/src/arkreactor/TypeChecker.cpp @@ -20,7 +20,7 @@ namespace Ark::types { if (i > 0) acc += ", "; - acc += types_to_str[static_cast(types[i])]; + acc += std::to_string(types[i]); } return acc; } @@ -82,7 +82,7 @@ namespace Ark::types if (i < args.size() && td.types[0] != ValueType::Any && std::ranges::find(td.types, args[i].valueType()) == td.types.end()) { displayArg(td, /* correct= */ false); - const auto type = types_to_str[static_cast(args[i].valueType())]; + const auto type = std::to_string(args[i].valueType()); fmt::dynamic_format_arg_store store; if (colorize) diff --git a/src/arkreactor/VM/VM.cpp b/src/arkreactor/VM/VM.cpp index 07694ad5..dd8f027a 100644 --- a/src/arkreactor/VM/VM.cpp +++ b/src/arkreactor/VM/VM.cpp @@ -165,13 +165,13 @@ namespace Ark fmt::format( "`{}' is a {}, not a Closure, can not get the field `{}' from it", m_state.m_symbols[context.last_symbol], - types_to_str[static_cast(closure->valueType())], + std::to_string(closure->valueType()), m_state.m_symbols[id])); else throwVMError(ErrorKind::Type, fmt::format( "{} is not a Closure, can not get the field `{}' from it", - types_to_str[static_cast(closure->valueType())], + std::to_string(closure->valueType()), m_state.m_symbols[id])); } @@ -1333,7 +1333,7 @@ namespace Ark TARGET(TYPE) { const Value* a = popAndResolveAsPtr(context); - push(Value(types_to_str[static_cast(a->valueType())]), context); + push(Value(std::to_string(a->valueType())), context); DISPATCH(); } @@ -1818,7 +1818,7 @@ namespace Ark const Value* cst = loadConstAsPtr(secondary_arg); push( cst->valueType() == ValueType::String && - types_to_str[static_cast(sym->valueType())] == cst->string() + std::to_string(sym->valueType()) == cst->string() ? Builtins::trueSym : Builtins::falseSym, context); @@ -1832,7 +1832,7 @@ namespace Ark const Value* cst = loadConstAsPtr(secondary_arg); push( cst->valueType() == ValueType::String && - types_to_str[static_cast(sym->valueType())] == cst->string() + std::to_string(sym->valueType()) == cst->string() ? Builtins::trueSym : Builtins::falseSym, context); diff --git a/src/arkreactor/VM/Value.cpp b/src/arkreactor/VM/Value.cpp index 7901f1c5..6de08834 100644 --- a/src/arkreactor/VM/Value.cpp +++ b/src/arkreactor/VM/Value.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -14,7 +15,7 @@ namespace Ark m_type(type) { if (type == ValueType::List) - m_value = std::vector(); + m_value = List_t(); else if (type == ValueType::String) m_value = std::string(); } @@ -23,11 +24,11 @@ namespace Ark m_type(ValueType::Number), m_value(static_cast(value)) {} - Value::Value(double value) noexcept : + Value::Value(const double value) noexcept : m_type(ValueType::Number), m_value(value) {} - Value::Value(const std::string& value) noexcept : + Value::Value(const String_t& value) noexcept : m_type(ValueType::String), m_value(value) {} @@ -43,7 +44,7 @@ namespace Ark m_type(ValueType::CProc), m_value(std::move(value)) {} - Value::Value(std::vector&& value) noexcept : + Value::Value(List_t&& value) noexcept : m_type(ValueType::List), m_value(std::move(value)) {} @@ -55,7 +56,11 @@ namespace Ark m_type(ValueType::User), m_value(value) {} - Value::Value(Value* ref) noexcept : + Value::Value(Dict_t&& value) noexcept : + m_type(ValueType::Dict), m_value(std::make_shared(std::move(value))) + {} + + Value::Value(Ref_t ref) noexcept : m_type(ValueType::Reference), m_value(ref) {} @@ -106,6 +111,9 @@ namespace Ark case ValueType::User: return fmt::format("{}", fmt::streamed(usertype())); + case ValueType::Dict: + return dict().toString(vm); + case ValueType::Nil: return "nil"; diff --git a/src/arkreactor/VM/Value/Dict.cpp b/src/arkreactor/VM/Value/Dict.cpp new file mode 100644 index 00000000..1a15a3f6 --- /dev/null +++ b/src/arkreactor/VM/Value/Dict.cpp @@ -0,0 +1,62 @@ +#include + +#include + +#include + +namespace Ark::internal +{ + void Dict::set(const Value& key, const Value& value) + { + m_dict.insert_or_assign(key, value); + } + + const Value& Dict::get(const Value& key) + { + if (const auto it = m_dict.find(key); it != m_dict.end()) + return it->second; + return Nil; + } + + bool Dict::contains(const Value& key) const + { + return m_dict.contains(key); + } + + void Dict::remove(const Value& key) + { + m_dict.erase(key); + } + + std::vector Dict::keys() + { + std::vector keys; + keys.reserve(m_dict.size()); + + for (auto&& key : std::ranges::views::keys(m_dict)) + keys.push_back(key); + return keys; + } + + std::size_t Dict::size() const + { + return m_dict.size(); + } + + std::string Dict::toString(VM& vm) const + { + std::string out = "{"; + + std::size_t i = 0; + for (const auto& [key, value] : m_dict) + { + out += key.toString(vm) + ": " + value.toString(vm); + + if (i + 1 != m_dict.size()) + out += ", "; + ++i; + } + + return out + "}"; + } +} diff --git a/src/arkreactor/VM/Value/Procedure.cpp b/src/arkreactor/VM/Value/Procedure.cpp index b29de1eb..6c66853a 100644 --- a/src/arkreactor/VM/Value/Procedure.cpp +++ b/src/arkreactor/VM/Value/Procedure.cpp @@ -10,10 +10,9 @@ namespace Ark return m_procedure(args, vm); } - Procedure::Procedure(PointerType c_pointer) - { - m_procedure = c_pointer; - } + Procedure::Procedure(PointerType c_pointer) : + m_procedure(c_pointer) + {} bool Procedure::operator<(const Procedure&) const noexcept { diff --git a/src/arkscript/main.cpp b/src/arkscript/main.cpp index f4d58d11..3b8d380e 100644 --- a/src/arkscript/main.cpp +++ b/src/arkscript/main.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -204,40 +205,28 @@ int main(int argc, char** argv) case mode::dev_info: { - fmt::println( - "Have been compiled with {}\n\n" - "sizeof(Ark::Value) = {}B\n" - " sizeof(Value_t) = {}B\n" - " sizeof(ValueType) = {}B\n" - " sizeof(Ark::Procedure) = {}B\n" - " sizeof(Ark::Closure) = {}B\n" - " sizeof(Ark::UserType) = {}B\n" - "\nVirtual Machine\n" - "sizeof(Ark::VM) = {}B\n" - " sizeof(Ark::State) = {}B\n" - " sizeof(Ark::Scope) = {}B\n" - " sizeof(ExecutionContext) = {}B\n" - "\nMisc\n" - " sizeof(vector) = {}B\n" - " sizeof(char) = {}B\n" - "\nsizeof(Node) = {}B", - ARK_COMPILER, - // value - sizeof(Ark::Value), - sizeof(Ark::Value::Value_t), - sizeof(Ark::ValueType), - sizeof(Ark::Procedure), - sizeof(Ark::internal::Closure), - sizeof(Ark::UserType), - // vm - sizeof(Ark::VM), - sizeof(Ark::State), - sizeof(Ark::internal::ScopeView), - sizeof(Ark::internal::ExecutionContext), - // misc - sizeof(std::vector), - sizeof(char), - sizeof(Ark::internal::Node)); + fmt::println("Compiler used: {}\n", ARK_COMPILER); + fmt::println("{:^34}|{:^8}|{:^10}", "Type", "SizeOf", "AlignOf"); + +#define ARK_PRINT_SIZE(type) fmt::println("{:<34}| {:<7}| {:<9}", #type, sizeof(type), alignof(type)) + ARK_PRINT_SIZE(char); + + ARK_PRINT_SIZE(Ark::Value); + ARK_PRINT_SIZE(Ark::Value::Value_t); + ARK_PRINT_SIZE(Ark::ValueType); + ARK_PRINT_SIZE(Ark::Procedure); + ARK_PRINT_SIZE(std::vector); + ARK_PRINT_SIZE(Ark::Value::Dict_t); + ARK_PRINT_SIZE(Ark::internal::Closure); + ARK_PRINT_SIZE(Ark::UserType); + + ARK_PRINT_SIZE(Ark::VM); + ARK_PRINT_SIZE(Ark::State); + ARK_PRINT_SIZE(Ark::internal::ScopeView); + ARK_PRINT_SIZE(Ark::internal::ExecutionContext); + + ARK_PRINT_SIZE(Ark::internal::Node); +#undef ARK_PRINT_SIZE break; } diff --git a/tests/fuzzing/arkscript.dict b/tests/fuzzing/arkscript.dict index d2ae9a84..7755730b 100644 --- a/tests/fuzzing/arkscript.dict +++ b/tests/fuzzing/arkscript.dict @@ -63,6 +63,7 @@ "builtin__io:makeDir" "builtin__io:removeFile" "time" +"builtin__sys:platform" "builtin__sys:exec" "builtin__sys:sleep" "format" @@ -82,3 +83,12 @@ "builtin__math:arcsin" "builtin__math:arctan" "random" +"async" +"await" +"dict" +"builtin__dict:get" +"builtin__dict:add" +"builtin__dict:contains" +"builtin__dict:remove" +"builtin__dict:keys" +"builtin__dict:size" diff --git a/tests/fuzzing/fuzzer-crash-triage.py b/tests/fuzzing/fuzzer-crash-triage.py index 5ecce88f..47b053fd 100755 --- a/tests/fuzzing/fuzzer-crash-triage.py +++ b/tests/fuzzing/fuzzer-crash-triage.py @@ -26,9 +26,9 @@ def run_file(file: str): def handle_command(i: int, count: int, file: str): command = input(f"[{i}/{count}] o,c,r,x,s,q,? > ").strip().lower() if command == "o": - os.rename(file, f"fct-ok/{os.path.basename(file)}") + os.rename(file, f"fct-ok/{os.path.basename(file)}.ark") elif command == "c": - os.rename(file, f"fct-bad/{os.path.basename(file)}") + os.rename(file, f"fct-bad/{os.path.basename(file)}.ark") elif command == "r": run_file(file) return True diff --git a/tests/unittests/Suites/TypeCheckerSuite.cpp b/tests/unittests/Suites/TypeCheckerSuite.cpp index 138c09a9..4ad04339 100644 --- a/tests/unittests/Suites/TypeCheckerSuite.cpp +++ b/tests/unittests/Suites/TypeCheckerSuite.cpp @@ -138,6 +138,9 @@ Input parse_input(const std::string& path) case Ark::ValueType::Closure: // unsupported [[fallthrough]]; + case Ark::ValueType::Dict: + // unsupported + [[fallthrough]]; case Ark::ValueType::User: // unsupported [[fallthrough]];