Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/CLI/src/Web.cpp
2725 views
1
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
#include "lua.h"
3
#include "lualib.h"
4
#include "luacode.h"
5
6
#include "Luau/Common.h"
7
#include "Luau/Frontend.h"
8
#include "Luau/BuiltinDefinitions.h"
9
10
#include <string>
11
#include <memory>
12
13
#include <string.h>
14
15
// Simple FileResolver for type checking on luau.org/demo
16
struct DemoFileResolver : Luau::FileResolver
17
{
18
std::optional<Luau::SourceCode> readSource(const Luau::ModuleName& name) override
19
{
20
auto it = source.find(name);
21
if (it == source.end())
22
return std::nullopt;
23
24
return Luau::SourceCode{it->second, Luau::SourceCode::Module};
25
}
26
27
std::optional<Luau::ModuleInfo> resolveModule(const Luau::ModuleInfo* context, Luau::AstExpr* expr, const Luau::TypeCheckLimits& limits) override
28
{
29
if (Luau::AstExprGlobal* g = expr->as<Luau::AstExprGlobal>())
30
return Luau::ModuleInfo{g->name.value};
31
32
return std::nullopt;
33
}
34
35
std::string getHumanReadableModuleName(const Luau::ModuleName& name) const override
36
{
37
return name;
38
}
39
40
std::optional<std::string> getEnvironmentForModule(const Luau::ModuleName& name) const override
41
{
42
return std::nullopt;
43
}
44
45
std::unordered_map<Luau::ModuleName, std::string> source;
46
};
47
48
// Simple ConfigResolver for type checking on luau.org/demo that defaults to Strict mode
49
struct DemoConfigResolver : Luau::ConfigResolver
50
{
51
DemoConfigResolver()
52
{
53
defaultConfig.mode = Luau::Mode::Strict;
54
}
55
56
virtual const Luau::Config& getConfig(const Luau::ModuleName& name, const Luau::TypeCheckLimits& limits) const override
57
{
58
return defaultConfig;
59
}
60
61
Luau::Config defaultConfig;
62
};
63
64
static void setupState(lua_State* L)
65
{
66
luaL_openlibs(L);
67
68
luaL_sandbox(L);
69
}
70
71
static std::string runCode(lua_State* L, const std::string& source)
72
{
73
size_t bytecodeSize = 0;
74
char* bytecode = luau_compile(source.data(), source.length(), nullptr, &bytecodeSize);
75
int result = luau_load(L, "=stdin", bytecode, bytecodeSize, 0);
76
free(bytecode);
77
78
if (result != 0)
79
{
80
size_t len;
81
const char* msg = lua_tolstring(L, -1, &len);
82
83
std::string error(msg, len);
84
lua_pop(L, 1);
85
86
return error;
87
}
88
89
lua_State* T = lua_newthread(L);
90
91
lua_pushvalue(L, -2);
92
lua_remove(L, -3);
93
lua_xmove(L, T, 1);
94
95
int status = lua_resume(T, NULL, 0);
96
97
if (status == 0)
98
{
99
int n = lua_gettop(T);
100
101
if (n)
102
{
103
luaL_checkstack(T, LUA_MINSTACK, "too many results to print");
104
lua_getglobal(T, "print");
105
lua_insert(T, 1);
106
lua_pcall(T, n, 0, 0);
107
}
108
109
lua_pop(L, 1); // pop T
110
return std::string();
111
}
112
else
113
{
114
std::string error;
115
116
lua_Debug ar;
117
if (lua_getinfo(L, 0, "sln", &ar))
118
{
119
error += ar.short_src;
120
error += ':';
121
error += std::to_string(ar.currentline);
122
error += ": ";
123
}
124
125
if (status == LUA_YIELD)
126
{
127
error += "thread yielded unexpectedly";
128
}
129
else if (const char* str = lua_tostring(T, -1))
130
{
131
error += str;
132
}
133
134
error += "\nstack backtrace:\n";
135
error += lua_debugtrace(T);
136
137
lua_pop(L, 1); // pop T
138
return error;
139
}
140
}
141
142
extern "C" const char* checkScript(const char* source, int useNewSolver)
143
{
144
static std::string finalCheckResult;
145
finalCheckResult.clear();
146
147
try
148
{
149
DemoFileResolver fileResolver;
150
DemoConfigResolver configResolver;
151
Luau::FrontendOptions options;
152
153
Luau::Frontend frontend(&fileResolver, &configResolver, options);
154
frontend.setLuauSolverMode(useNewSolver ? Luau::SolverMode::New : Luau::SolverMode::Old);
155
// Add Luau builtins
156
Luau::unfreeze(frontend.globals.globalTypes);
157
Luau::registerBuiltinGlobals(frontend, frontend.globals);
158
Luau::freeze(frontend.globals.globalTypes);
159
160
// restart
161
frontend.clear();
162
fileResolver.source.clear();
163
164
fileResolver.source["main"] = source;
165
166
Luau::CheckResult checkResult = frontend.check("main");
167
for (const Luau::TypeError& err : checkResult.errors)
168
{
169
if (!finalCheckResult.empty())
170
finalCheckResult += "\n";
171
finalCheckResult += std::to_string(err.location.begin.line + 1);
172
finalCheckResult += ": ";
173
finalCheckResult += Luau::toString(err);
174
}
175
}
176
catch (const std::exception& e)
177
{
178
finalCheckResult = e.what();
179
}
180
181
return finalCheckResult.empty() ? nullptr : finalCheckResult.c_str();
182
}
183
184
extern "C" const char* executeScript(const char* source)
185
{
186
// setup flags
187
for (Luau::FValue<bool>* flag = Luau::FValue<bool>::list; flag; flag = flag->next)
188
if (strncmp(flag->name, "Luau", 4) == 0)
189
flag->value = true;
190
191
// create new state
192
std::unique_ptr<lua_State, void (*)(lua_State*)> globalState(luaL_newstate(), lua_close);
193
lua_State* L = globalState.get();
194
195
// setup state
196
setupState(L);
197
198
// sandbox thread
199
luaL_sandboxthread(L);
200
201
// static string for caching result (prevents dangling ptr on function exit)
202
static std::string result;
203
204
// run code + collect error
205
result = runCode(L, source);
206
207
return result.empty() ? nullptr : result.c_str();
208
}
209
210