diff --git a/cmake/Toolchain-wasm32-web.cmake b/cmake/Toolchain-wasm32-web.cmake new file mode 100644 index 0000000..f08a2c2 --- /dev/null +++ b/cmake/Toolchain-wasm32-web.cmake @@ -0,0 +1,32 @@ + +set(CMAKE_SYSTEM_PROCESSOR "wasm32" CACHE STRING "" FORCE) +set(CMAKE_SYSTEM_NAME "Emscripten" CACHE STRING "" FORCE) +set(CMAKE_SYSTEM_VERSION 1) +set(CMAKE_CROSSCOMPILING TRUE) +set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE) +set(UNIX 1) +set(SYSTRIPLET "${CMAKE_SYSTEM_PROCESSOR}-unknown-emscripten" CACHE STRING "" FORCE) +add_compile_definitions(_LIBCPP_ENABLE_EXPERIMENTAL) +set(TOOLCHAIN_PATH "/" CACHE PATH "Path to toolchain native sysroot") +SET(TARGET_SYSROOT_PATH "/" CACHE PATH "Path to toolchain target sysroot") + +find_program(EMCC NAMES emcc REQUIRED) +find_program(EMPP NAMES em++ REQUIRED) +find_program(EMAR NAMES emar REQUIRED) +find_program(EMRANLIB NAMES emranlib REQUIRED) + +SET(CMAKE_FORCE_C_COMPILER ${EMCC}) +SET(CMAKE_FORCE_CXX_COMPILER ${EMPP}) +SET(CMAKE_C_COMPILER ${CMAKE_FORCE_C_COMPILER}) +SET(CMAKE_CXX_COMPILER ${CMAKE_FORCE_CXX_COMPILER}) +set(CMAKE_CXX_COMPILER_AR ${EMAR}) +set(CMAKE_AR ${EMAR}) +set(CMAKE_CXX_COMPILER_RANLIB ${EMRANLIB}) +set(CMAKE_RANLIB ${EMRANLIB}) + +add_compile_options( -mbulk-memory ) +add_compile_options( -sUSE_BOOST_HEADERS=1) + +add_link_options( -sALLOW_MEMORY_GROWTH -sMAXIMUM_MEMORY=4294901760 ) + +set(EMSCRIPTEN_ENV "web") diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt new file mode 100644 index 0000000..174285f --- /dev/null +++ b/source/CMakeLists.txt @@ -0,0 +1,34 @@ + +cmake_minimum_required(VERSION 3.20) +project(cppdecl) + +set(CMAKE_CXX_STANDARD 20) + + +if(CMAKE_CXX_COMPILER MATCHES "/em\\+\\+(-[a-zA-Z0-9.])?$") + message(" * C++ compiler: Emscripten") + set(CMAKE_CXX_COMPILER_ID "Emscripten") + if ("${EMSCRIPTEN_ENV}" STREQUAL "web") + set(CMAKE_EXECUTABLE_SUFFIX ".html") + else() + set(CMAKE_EXECUTABLE_SUFFIX ".js") + endif() + set(CMAKE_CXX_BYTE_ORDER "LITTLE_ENDIAN") +else() + message(" * C++ compiler: ${CMAKE_CXX_COMPILER_ID}") +endif() + +if ("${EMSCRIPTEN_ENV}" STREQUAL "web") + + add_executable(index cppdecl-shell.cpp ) + target_include_directories(index PUBLIC ../include) + target_link_options(index PUBLIC --shell-file ${CMAKE_SOURCE_DIR}/cppdecl-shell.html) + target_link_options(index PUBLIC -sEXPORTED_FUNCTIONS=_main,_malloc,_free -sEXPORTED_RUNTIME_METHODS=UTF8ToString,stringToUTF8,lengthBytesUTF8,ccall,cwrap) + +else() + add_executable(cppdecl repl.cpp) + target_include_directories(cppdecl PUBLIC ../include) + + add_executable(tests tests.cpp) + target_include_directories(tests PUBLIC ../include) +endif() diff --git a/source/cppdecl-shell.cpp b/source/cppdecl-shell.cpp new file mode 100644 index 0000000..9dcbd08 --- /dev/null +++ b/source/cppdecl-shell.cpp @@ -0,0 +1,134 @@ +#include "cppdecl/declarations/parse.h" +#include "cppdecl/declarations/simplify.h" +#include "cppdecl/declarations/to_string.h" +#include "cppdecl/type_name.h" +#include +#include +#include + + +std::string escape_xml(std::string_view sv) { + std::string result; + result.reserve(sv.size()); + for (size_t i = 0; i < sv.size(); i++) { + uint8_t c = sv[i]; + + if ((c < 32 and c != '\n') or c == 127) { + continue; + } + switch (c) { + case '<': + result += "<"; + break; + case '>': + result += ">"; + break; + case '&': + result += "&"; + break; + case '\n': + result += "
\n"; + break; + case '"': + result += """; + break; + //case ' ': + // result += " "; + break; + default: + result += c; + } + } + constexpr std::array lre = {u8"\u202A"}; // Left-to-Right Embedding + constexpr std::array rle = {u8"\u202B"}; // Right-to-Left Embedding + constexpr std::array pdf = {u8"\u202C"}; // Pop Directional Formatting + constexpr std::array lro = {u8"\u202D"}; // Left-to-Right Override + constexpr std::array rlo = {u8"\u202E"}; // Right-to-Left Override + constexpr std::array lri = {u8"\u2066"}; // Left-to-Right isolate + constexpr std::array rli = {u8"\u2067"}; // Right-to-Left isolate + constexpr std::array fsi = {u8"\u2068"}; // First Strong isolate + constexpr std::array pdi = {u8"\u2069"}; // Pop Directional isolate + + constexpr std::array, 9> control = {lre, rle, pdf, lro, rlo, lri, rli, fsi, pdi}; + for (auto& sec : control) { + auto bidi = std::string_view(reinterpret_cast(sec.data()), sec.size() - 1); + auto pos = result.find(bidi); + while (pos != std::string::npos) { + result.replace(pos, sec.size(), ""); + pos = result.find(bidi); + } + } + return result; +} + +namespace cppdecl{ +void parseText(std::string_view input) { + + auto ret = cppdecl::ParseDecl(input, cppdecl::ParseDeclFlags::accept_everything); + std::ostringstream out; + + if (auto error = std::get_if(&ret)) + { + out << "Parse error: " << error->message << '\n'; + } + else + { + if (!input.empty()) + out << "Unparsed junk at the end of input.\n"; + + auto &decl = std::get(ret); + + out << "\n--- Parsed to:\n"; + out << cppdecl::ToString(decl, {}) << '\n'; + + cppdecl::MaybeAmbiguousDecl simplified_decl = decl; + cppdecl::Simplify(cppdecl::SimplifyFlags::all, simplified_decl); + if (simplified_decl != decl) + { + out << "\n--- Simplifies to:\n"; + out << cppdecl::ToCode(simplified_decl, {}) << '\n'; + + out << "\n--- The simplified version parses to:\n"; + out << cppdecl::ToString(simplified_decl, {}) << '\n'; + } + } + + auto demangled = out.str(); + auto escaped = escape_xml(demangled); + escaped = demangled; + EM_ASM_({ document.getElementById('demangled').value = UTF8ToString($0, $1); }, escaped.data(), escaped.size()); +} +} + + +extern "C" { +EMSCRIPTEN_KEEPALIVE +void parseText(const char* name1, int nlength1) { + cppdecl::parseText(std::string_view(name1, nlength1)); +} +} + +void init_loop(void*) { +#ifdef __EMSCRIPTEN__ + emscripten_cancel_main_loop(); + + EM_ASM_({ + Module.demangleText = Module.cwrap('demangleText', null, [ 'number', 'number' ]); + is_emscripten_initialized = 1; + set_darkmode(darkmode); + if (pending_demangle) { + document.getElementById('mangled').value = pending_demangle; + demangle_text(pending_demangle); + pending_demangle = null; + } + + }); + +#endif +} + +int main(int, char**) { + + emscripten_set_main_loop_arg(init_loop, nullptr, 0, false); + return 0; +} diff --git a/source/cppdecl-shell.html b/source/cppdecl-shell.html new file mode 100644 index 0000000..6b7de1a --- /dev/null +++ b/source/cppdecl-shell.html @@ -0,0 +1,94 @@ + + + + + + + +cppdecl + + + + +
+
+
+ + + +
+
+
+ +
+ + +{{{ SCRIPT }}} + + +