mirror of
https://github.com/luau-lang/luau.git
synced 2024-11-15 14:25:44 +08:00
Feature: Web REPL using Emscripten (#138)
Currently doesn't include the new page into navigation since we aren't building the .js files anywhere.
This commit is contained in:
parent
d6b3346f58
commit
aec8fbfd0f
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@
|
|||||||
^default.prof*
|
^default.prof*
|
||||||
^fuzz-*
|
^fuzz-*
|
||||||
^luau$
|
^luau$
|
||||||
|
/.vs
|
||||||
|
44
CLI/Repl.cpp
44
CLI/Repl.cpp
@ -198,6 +198,11 @@ static std::string runCode(lua_State* L, const std::string& source)
|
|||||||
error += "\nstack backtrace:\n";
|
error += "\nstack backtrace:\n";
|
||||||
error += lua_debugtrace(T);
|
error += lua_debugtrace(T);
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
// nicer formatting for errors in web repl
|
||||||
|
error = "Error:" + error;
|
||||||
|
#endif
|
||||||
|
|
||||||
fprintf(stdout, "%s", error.c_str());
|
fprintf(stdout, "%s", error.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,6 +210,44 @@ static std::string runCode(lua_State* L, const std::string& source)
|
|||||||
return std::string();
|
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<bool>* flag = Luau::FValue<bool>::list; flag; flag = flag->next)
|
||||||
|
if (strncmp(flag->name, "Luau", 4) == 0)
|
||||||
|
flag->value = true;
|
||||||
|
|
||||||
|
// create new state
|
||||||
|
std::unique_ptr<lua_State, void (*)(lua_State*)> 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<std::string>& completions)
|
static void completeIndexer(lua_State* L, const char* editBuffer, size_t start, std::vector<std::string>& completions)
|
||||||
{
|
{
|
||||||
std::string_view lookup = editBuffer + start;
|
std::string_view lookup = editBuffer + start;
|
||||||
@ -547,3 +590,4 @@ int main(int argc, char** argv)
|
|||||||
return failed;
|
return failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
@ -17,17 +17,26 @@ add_library(Luau.VM STATIC)
|
|||||||
|
|
||||||
if(LUAU_BUILD_CLI)
|
if(LUAU_BUILD_CLI)
|
||||||
add_executable(Luau.Repl.CLI)
|
add_executable(Luau.Repl.CLI)
|
||||||
|
if(NOT EMSCRIPTEN)
|
||||||
add_executable(Luau.Analyze.CLI)
|
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
|
# 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.Repl.CLI PROPERTIES OUTPUT_NAME luau)
|
||||||
|
|
||||||
|
if(NOT EMSCRIPTEN)
|
||||||
set_target_properties(Luau.Analyze.CLI PROPERTIES OUTPUT_NAME luau-analyze)
|
set_target_properties(Luau.Analyze.CLI PROPERTIES OUTPUT_NAME luau-analyze)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(LUAU_BUILD_TESTS)
|
if(LUAU_BUILD_TESTS AND NOT EMSCRIPTEN)
|
||||||
add_executable(Luau.UnitTest)
|
add_executable(Luau.UnitTest)
|
||||||
add_executable(Luau.Conformance)
|
add_executable(Luau.Conformance)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(Sources.cmake)
|
include(Sources.cmake)
|
||||||
|
|
||||||
target_compile_features(Luau.Ast PUBLIC cxx_std_17)
|
target_compile_features(Luau.Ast PUBLIC cxx_std_17)
|
||||||
@ -53,10 +62,6 @@ if(MSVC)
|
|||||||
else()
|
else()
|
||||||
list(APPEND LUAU_OPTIONS -Wall) # All warnings
|
list(APPEND LUAU_OPTIONS -Wall) # All warnings
|
||||||
list(APPEND LUAU_OPTIONS -Werror) # Warnings are errors
|
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()
|
endif()
|
||||||
|
|
||||||
target_compile_options(Luau.Ast PRIVATE ${LUAU_OPTIONS})
|
target_compile_options(Luau.Ast PRIVATE ${LUAU_OPTIONS})
|
||||||
@ -65,7 +70,10 @@ target_compile_options(Luau.VM PRIVATE ${LUAU_OPTIONS})
|
|||||||
|
|
||||||
if(LUAU_BUILD_CLI)
|
if(LUAU_BUILD_CLI)
|
||||||
target_compile_options(Luau.Repl.CLI PRIVATE ${LUAU_OPTIONS})
|
target_compile_options(Luau.Repl.CLI PRIVATE ${LUAU_OPTIONS})
|
||||||
|
|
||||||
|
if(NOT EMSCRIPTEN)
|
||||||
target_compile_options(Luau.Analyze.CLI PRIVATE ${LUAU_OPTIONS})
|
target_compile_options(Luau.Analyze.CLI PRIVATE ${LUAU_OPTIONS})
|
||||||
|
endif()
|
||||||
|
|
||||||
target_include_directories(Luau.Repl.CLI PRIVATE extern)
|
target_include_directories(Luau.Repl.CLI PRIVATE extern)
|
||||||
target_link_libraries(Luau.Repl.CLI PRIVATE Luau.Compiler Luau.VM)
|
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)
|
target_link_libraries(Luau.Repl.CLI PRIVATE pthread)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(NOT EMSCRIPTEN)
|
||||||
target_link_libraries(Luau.Analyze.CLI PRIVATE Luau.Analysis)
|
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()
|
endif()
|
||||||
|
|
||||||
if(LUAU_BUILD_TESTS)
|
if(LUAU_BUILD_TESTS AND NOT EMSCRIPTEN)
|
||||||
target_compile_options(Luau.UnitTest PRIVATE ${LUAU_OPTIONS})
|
target_compile_options(Luau.UnitTest PRIVATE ${LUAU_OPTIONS})
|
||||||
target_include_directories(Luau.UnitTest PRIVATE extern)
|
target_include_directories(Luau.UnitTest PRIVATE extern)
|
||||||
target_link_libraries(Luau.UnitTest PRIVATE Luau.Analysis Luau.Compiler)
|
target_link_libraries(Luau.UnitTest PRIVATE Luau.Analysis Luau.Compiler)
|
||||||
|
@ -27,3 +27,7 @@ pages:
|
|||||||
url: /profile
|
url: /profile
|
||||||
- title: Library
|
- title: Library
|
||||||
url: /library
|
url: /library
|
||||||
|
|
||||||
|
# Remove demo pages until solution is found
|
||||||
|
# - title: Demo
|
||||||
|
# url: /demo
|
||||||
|
50
docs/_includes/repl.html
Normal file
50
docs/_includes/repl.html
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<form>
|
||||||
|
<div>
|
||||||
|
<label>Script:</label>
|
||||||
|
<br>
|
||||||
|
<textarea rows="10" cols="70" id="script">print("Hello World!")</textarea>
|
||||||
|
<br><br>
|
||||||
|
<button onclick="clearInput(); return false;">
|
||||||
|
Clear Input
|
||||||
|
</button>
|
||||||
|
<button onclick="executeScript(); return false;">
|
||||||
|
Run
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<br><br>
|
||||||
|
<div>
|
||||||
|
<label>Output:</label>
|
||||||
|
<br>
|
||||||
|
<textarea readonly rows="10" cols="70" id="output"></textarea>
|
||||||
|
<br><br>
|
||||||
|
<button onclick="clearOutput(); return false;">
|
||||||
|
Clear Output
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function output(text) {
|
||||||
|
document.getElementById("output").value += "[" + new Date().toLocaleTimeString() + "] " + text.replace('stdin:', '') + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
var Module = {
|
||||||
|
'print': function (msg) { output(msg) }
|
||||||
|
};
|
||||||
|
|
||||||
|
function clearInput() {
|
||||||
|
document.getElementById("script").value = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearOutput() {
|
||||||
|
document.getElementById("output").value = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function executeScript() {
|
||||||
|
var err = Module.ccall('executeScript', 'string', ['string'], [document.getElementById("script").value]);
|
||||||
|
if (err) {
|
||||||
|
output('Error:' + err.replace('stdin:', ''));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script async src="assets/luau/luau.js"></script>
|
6
docs/_pages/demo.md
Normal file
6
docs/_pages/demo.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
permalink: /demo
|
||||||
|
title: Demo
|
||||||
|
---
|
||||||
|
|
||||||
|
{% include repl.html %}
|
Loading…
Reference in New Issue
Block a user