1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
#include <iostream>
#include <string>
#include <string_view>
#include "yuescript/yue_compiler.h"
extern "C" {
#include "lauxlib.h"
#include "lua.h"
#include "lualib.h"
int luaopen_yue(lua_State* L);
}
namespace {
size_t moduleCount(lua_State* L) {
lua_pushliteral(L, "__yue_modules__");
lua_rawget(L, LUA_REGISTRYINDEX);
#if LUA_VERSION_NUM > 501
const size_t count = lua_isnil(L, -1) ? 0 : lua_rawlen(L, -1);
#else
const size_t count = lua_isnil(L, -1) ? 0 : lua_objlen(L, -1);
#endif
lua_pop(L, 1);
return count;
}
bool expect(bool condition, std::string_view message) {
if (!condition) {
std::cerr << "same_module state test failed: " << message << '\n';
}
return condition;
}
} // namespace
int main() {
constexpr std::string_view defineAndUse =
"macro double = (x) -> \"#{x} * 2\"\n"
"result = $double 5\n";
constexpr std::string_view failAfterMacro =
"macro double = (x) -> \"#{x} * 2\"\n"
"result = $missing 5\n";
constexpr std::string_view useOnly = "result = $double 7\n";
lua_State* L = luaL_newstate();
if (!expect(L != nullptr, "failed to create Lua state")) return 1;
luaL_openlibs(L);
#if LUA_VERSION_NUM > 501
luaL_requiref(L, "yue", luaopen_yue, 0);
#else
lua_pushcfunction(L, luaopen_yue);
lua_call(L, 0, 1);
#endif
lua_pop(L, 1);
yue::YueConfig config;
bool passed = true;
{
yue::YueCompiler compiler(L, nullptr, true);
std::string expectedCodes;
for (int i = 0; i < 500; i++) {
auto result = compiler.compile(defineAndUse, config);
passed &= expect(!result.error, "repeated compilation returned an error");
if (i == 0) {
expectedCodes = result.codes;
} else {
passed &= expect(result.codes == expectedCodes, "repeated compilation changed its output");
}
}
passed &= expect(moduleCount(L) == 1, "repeated compilation grew the module registry");
}
yue::YueCompiler::clear(L);
{
yue::YueCompiler compiler(L, nullptr, true);
auto failed = compiler.compile(failAfterMacro, config);
passed &= expect(failed.error.has_value(), "expected macro expansion failure");
auto next = compiler.compile(useOnly, config);
passed &= expect(next.error.has_value(), "failed compilation leaked a macro into the next compilation");
passed &= expect(moduleCount(L) == 1, "failed compilation grew the module registry");
}
yue::YueCompiler::clear(L);
{
yue::YueCompiler compiler(L, nullptr, true);
passed &= expect(!compiler.compile(defineAndUse, config).error, "initial live-clear compilation failed");
yue::YueCompiler::clear(L);
passed &= expect(!compiler.compile(defineAndUse, config).error, "compiler did not rebuild a cleared registry");
passed &= expect(moduleCount(L) == 1, "rebuilt registry has an unexpected module count");
}
yue::YueCompiler::clear(L);
{
yue::YueCompiler compiler(L, nullptr, false);
passed &= expect(!compiler.compile(defineAndUse, config).error, "isolated compilation failed");
passed &= expect(moduleCount(L) == 0, "sameModule=false retained a module");
}
yue::YueCompiler::clear(L);
lua_close(L);
if (passed) {
std::cout << "same_module state test passed\n";
return 0;
}
return 1;
}
|