From aec8fbfd0facdba1e1f6dcb070742000d92fa5ed Mon Sep 17 00:00:00 2001 From: Pelanyo Kamara Date: Wed, 10 Nov 2021 16:40:46 +0000 Subject: [PATCH] Feature: Web REPL using Emscripten (#138) Currently doesn't include the new page into navigation since we aren't building the .js files anywhere. --- .gitignore | 1 + CLI/Repl.cpp | 44 ++++++++++++++++++++++++++++++++++ CMakeLists.txt | 38 +++++++++++++++++++++-------- docs/_data/navigation.yml | 4 ++++ docs/_includes/repl.html | 50 +++++++++++++++++++++++++++++++++++++++ docs/_pages/demo.md | 6 +++++ 6 files changed, 133 insertions(+), 10 deletions(-) create mode 100644 docs/_includes/repl.html create mode 100644 docs/_pages/demo.md diff --git a/.gitignore b/.gitignore index 0b2422ce..fa11b45b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ ^default.prof* ^fuzz-* ^luau$ +/.vs diff --git a/CLI/Repl.cpp b/CLI/Repl.cpp index 1c5305a4..63b86a80 100644 --- a/CLI/Repl.cpp +++ b/CLI/Repl.cpp @@ -198,6 +198,11 @@ static std::string runCode(lua_State* L, const std::string& source) error += "\nstack backtrace:\n"; error += lua_debugtrace(T); +#ifdef __EMSCRIPTEN__ + // nicer formatting for errors in web repl + error = "Error:" + error; +#endif + fprintf(stdout, "%s", error.c_str()); } @@ -205,6 +210,44 @@ static std::string runCode(lua_State* L, const std::string& source) return std::string(); } +#ifdef __EMSCRIPTEN__ +extern "C" +{ + const char* executeScript(const char* source) + { + // static string for caching result (prevents dangling ptr on function exit) + static std::string result; + + // setup flags + for (Luau::FValue* flag = Luau::FValue::list; flag; flag = flag->next) + if (strncmp(flag->name, "Luau", 4) == 0) + flag->value = true; + + // create new state + std::unique_ptr globalState(luaL_newstate(), lua_close); + lua_State* L = globalState.get(); + + // setup state + setupState(L); + + // sandbox thread + luaL_sandboxthread(L); + + // run code + collect error + std::string error = runCode(L, source); + result = error; + + if (error.length()) + { + return result.c_str(); + } + return NULL; + } +} +#endif + +// Excluded from emscripten compilation to avoid -Wunused-function errors. +#ifndef __EMSCRIPTEN__ static void completeIndexer(lua_State* L, const char* editBuffer, size_t start, std::vector& completions) { std::string_view lookup = editBuffer + start; @@ -547,3 +590,4 @@ int main(int argc, char** argv) return failed; } } +#endif diff --git a/CMakeLists.txt b/CMakeLists.txt index d6598f2a..36014a98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,17 +17,26 @@ add_library(Luau.VM STATIC) if(LUAU_BUILD_CLI) add_executable(Luau.Repl.CLI) - add_executable(Luau.Analyze.CLI) + if(NOT EMSCRIPTEN) + add_executable(Luau.Analyze.CLI) + else() + # add -fexceptions for emscripten to allow exceptions to be caught in C++ + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions") + endif() # This also adds target `name` on Linux/macOS and `name.exe` on Windows set_target_properties(Luau.Repl.CLI PROPERTIES OUTPUT_NAME luau) - set_target_properties(Luau.Analyze.CLI PROPERTIES OUTPUT_NAME luau-analyze) + + if(NOT EMSCRIPTEN) + set_target_properties(Luau.Analyze.CLI PROPERTIES OUTPUT_NAME luau-analyze) + endif() endif() -if(LUAU_BUILD_TESTS) +if(LUAU_BUILD_TESTS AND NOT EMSCRIPTEN) add_executable(Luau.UnitTest) add_executable(Luau.Conformance) endif() + include(Sources.cmake) target_compile_features(Luau.Ast PUBLIC cxx_std_17) @@ -53,10 +62,6 @@ if(MSVC) else() list(APPEND LUAU_OPTIONS -Wall) # All warnings list(APPEND LUAU_OPTIONS -Werror) # Warnings are errors - - if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - list(APPEND LUAU_OPTIONS -Wno-unused) # GCC considers variables declared/checked in if() as unused - endif() endif() target_compile_options(Luau.Ast PRIVATE ${LUAU_OPTIONS}) @@ -65,7 +70,10 @@ target_compile_options(Luau.VM PRIVATE ${LUAU_OPTIONS}) if(LUAU_BUILD_CLI) target_compile_options(Luau.Repl.CLI PRIVATE ${LUAU_OPTIONS}) - target_compile_options(Luau.Analyze.CLI PRIVATE ${LUAU_OPTIONS}) + + if(NOT EMSCRIPTEN) + target_compile_options(Luau.Analyze.CLI PRIVATE ${LUAU_OPTIONS}) + endif() target_include_directories(Luau.Repl.CLI PRIVATE extern) target_link_libraries(Luau.Repl.CLI PRIVATE Luau.Compiler Luau.VM) @@ -74,10 +82,20 @@ if(LUAU_BUILD_CLI) target_link_libraries(Luau.Repl.CLI PRIVATE pthread) endif() - target_link_libraries(Luau.Analyze.CLI PRIVATE Luau.Analysis) + if(NOT EMSCRIPTEN) + target_link_libraries(Luau.Analyze.CLI PRIVATE Luau.Analysis) + endif() + + if(EMSCRIPTEN) + # declare exported functions to emscripten + target_link_options(Luau.Repl.CLI PRIVATE -sEXPORTED_FUNCTIONS=['_executeScript'] -sEXPORTED_RUNTIME_METHODS=['ccall','cwrap'] -fexceptions) + + # custom output directory for wasm + js file + set_target_properties(Luau.Repl.CLI PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/docs/assets/luau) + endif() endif() -if(LUAU_BUILD_TESTS) +if(LUAU_BUILD_TESTS AND NOT EMSCRIPTEN) target_compile_options(Luau.UnitTest PRIVATE ${LUAU_OPTIONS}) target_include_directories(Luau.UnitTest PRIVATE extern) target_link_libraries(Luau.UnitTest PRIVATE Luau.Analysis Luau.Compiler) diff --git a/docs/_data/navigation.yml b/docs/_data/navigation.yml index 63058963..c828b2d4 100644 --- a/docs/_data/navigation.yml +++ b/docs/_data/navigation.yml @@ -27,3 +27,7 @@ pages: url: /profile - title: Library url: /library + +# Remove demo pages until solution is found +# - title: Demo +# url: /demo diff --git a/docs/_includes/repl.html b/docs/_includes/repl.html new file mode 100644 index 00000000..73c5ba40 --- /dev/null +++ b/docs/_includes/repl.html @@ -0,0 +1,50 @@ +
+
+ +
+ +

+ + +
+

+
+ +
+ +

+ +
+
+ + + diff --git a/docs/_pages/demo.md b/docs/_pages/demo.md new file mode 100644 index 00000000..fefa4b20 --- /dev/null +++ b/docs/_pages/demo.md @@ -0,0 +1,6 @@ +--- +permalink: /demo +title: Demo +--- + +{% include repl.html %}