diff options
| author | Li Jin <dragon-fly@qq.com> | 2023-01-31 18:17:31 +0800 |
|---|---|---|
| committer | Li Jin <dragon-fly@qq.com> | 2023-01-31 18:17:31 +0800 |
| commit | e3e45fb330e29cc9b203a70b649e61f62697f88d (patch) | |
| tree | 114c8e38a133e875e3a2467a69922e7771f513a1 /src | |
| parent | 5fa51d49705e25d284c4adb16edb625d85e0c601 (diff) | |
| download | yuescript-e3e45fb330e29cc9b203a70b649e61f62697f88d.tar.gz yuescript-e3e45fb330e29cc9b203a70b649e61f62697f88d.tar.bz2 yuescript-e3e45fb330e29cc9b203a70b649e61f62697f88d.zip | |
fix stack overflow issue in yue.to_ast().
Diffstat (limited to '')
| -rw-r--r-- | src/yue.cpp | 18 | ||||
| -rw-r--r-- | src/yuescript/yue_compiler.cpp | 4 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.cpp | 5 | ||||
| -rw-r--r-- | src/yuescript/yuescript.cpp | 156 |
4 files changed, 124 insertions, 59 deletions
diff --git a/src/yue.cpp b/src/yue.cpp index 5679e58..7adde70 100644 --- a/src/yue.cpp +++ b/src/yue.cpp | |||
| @@ -270,15 +270,6 @@ int main(int narg, const char** args) { | |||
| 270 | ; | 270 | ; |
| 271 | #ifndef YUE_COMPILER_ONLY | 271 | #ifndef YUE_COMPILER_ONLY |
| 272 | if (narg == 1) { | 272 | if (narg == 1) { |
| 273 | lua_State* L = luaL_newstate(); | ||
| 274 | openlibs(L); | ||
| 275 | DEFER(lua_close(L)); | ||
| 276 | pushYue(L, "insert_loader"sv); | ||
| 277 | if (lua_pcall(L, 0, 0, 0) != 0) { | ||
| 278 | std::cout << lua_tostring(L, -1) << '\n'; | ||
| 279 | return 1; | ||
| 280 | } | ||
| 281 | int count = 0; | ||
| 282 | linenoise::SetMultiLine(false); | 273 | linenoise::SetMultiLine(false); |
| 283 | linenoise::SetCompletionCallback([](const char* editBuffer, std::vector<std::string>& completions) { | 274 | linenoise::SetCompletionCallback([](const char* editBuffer, std::vector<std::string>& completions) { |
| 284 | std::string buf = editBuffer; | 275 | std::string buf = editBuffer; |
| @@ -326,6 +317,15 @@ int main(int narg, const char** args) { | |||
| 326 | break; | 317 | break; |
| 327 | } | 318 | } |
| 328 | }); | 319 | }); |
| 320 | lua_State* L = luaL_newstate(); | ||
| 321 | openlibs(L); | ||
| 322 | DEFER(lua_close(L)); | ||
| 323 | pushYue(L, "insert_loader"sv); | ||
| 324 | if (lua_pcall(L, 0, 0, 0) != 0) { | ||
| 325 | std::cout << lua_tostring(L, -1) << '\n'; | ||
| 326 | return 1; | ||
| 327 | } | ||
| 328 | int count = 0; | ||
| 329 | std::cout << "Yuescript "sv << yue::version << '\n'; | 329 | std::cout << "Yuescript "sv << yue::version << '\n'; |
| 330 | while (true) { | 330 | while (true) { |
| 331 | count++; | 331 | count++; |
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 83933d1..0cf643f 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
| @@ -32,7 +32,9 @@ extern "C" { | |||
| 32 | 32 | ||
| 33 | #if LUA_VERSION_NUM > 501 | 33 | #if LUA_VERSION_NUM > 501 |
| 34 | #ifndef LUA_COMPAT_5_1 | 34 | #ifndef LUA_COMPAT_5_1 |
| 35 | #ifndef lua_objlen | ||
| 35 | #define lua_objlen lua_rawlen | 36 | #define lua_objlen lua_rawlen |
| 37 | #endif // lua_objlen | ||
| 36 | #endif // LUA_COMPAT_5_1 | 38 | #endif // LUA_COMPAT_5_1 |
| 37 | #endif // LUA_VERSION_NUM | 39 | #endif // LUA_VERSION_NUM |
| 38 | 40 | ||
| @@ -71,7 +73,7 @@ static std::unordered_set<std::string> Metamethods = { | |||
| 71 | "close"s // Lua 5.4 | 73 | "close"s // Lua 5.4 |
| 72 | }; | 74 | }; |
| 73 | 75 | ||
| 74 | const std::string_view version = "0.15.25"sv; | 76 | const std::string_view version = "0.15.26"sv; |
| 75 | const std::string_view extension = "yue"sv; | 77 | const std::string_view extension = "yue"sv; |
| 76 | 78 | ||
| 77 | class YueCompilerImpl { | 79 | class YueCompilerImpl { |
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 5bb4817..e70c4a0 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp | |||
| @@ -869,9 +869,10 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) { | |||
| 869 | codes = codes.substr(3); | 869 | codes = codes.substr(3); |
| 870 | } | 870 | } |
| 871 | try { | 871 | try { |
| 872 | res.codes = std::make_unique<input>(); | ||
| 873 | if (!codes.empty()) { | 872 | if (!codes.empty()) { |
| 874 | *(res.codes) = _converter.from_bytes(&codes.front(), &codes.back() + 1); | 873 | res.codes = std::make_unique<input>(_converter.from_bytes(&codes.front(), &codes.back() + 1)); |
| 874 | } else { | ||
| 875 | res.codes = std::make_unique<input>(); | ||
| 875 | } | 876 | } |
| 876 | } catch (const std::range_error&) { | 877 | } catch (const std::range_error&) { |
| 877 | res.error = "invalid text encoding"sv; | 878 | res.error = "invalid text encoding"sv; |
diff --git a/src/yuescript/yuescript.cpp b/src/yuescript/yuescript.cpp index b01c3eb..20fa258 100644 --- a/src/yuescript/yuescript.cpp +++ b/src/yuescript/yuescript.cpp | |||
| @@ -22,6 +22,14 @@ extern "C" { | |||
| 22 | #include "lauxlib.h" | 22 | #include "lauxlib.h" |
| 23 | #include "lua.h" | 23 | #include "lua.h" |
| 24 | 24 | ||
| 25 | #if LUA_VERSION_NUM > 501 | ||
| 26 | #ifndef LUA_COMPAT_5_1 | ||
| 27 | #ifndef lua_objlen | ||
| 28 | #define lua_objlen lua_rawlen | ||
| 29 | #endif // lua_objlen | ||
| 30 | #endif // LUA_COMPAT_5_1 | ||
| 31 | #endif // LUA_VERSION_NUM | ||
| 32 | |||
| 25 | static const char yuescriptCodes[] = | 33 | static const char yuescriptCodes[] = |
| 26 | #include "yuescript/yuescript.h" | 34 | #include "yuescript/yuescript.h" |
| 27 | ; | 35 | ; |
| @@ -142,6 +150,14 @@ static int yuetolua(lua_State* L) { | |||
| 142 | return 3; | 150 | return 3; |
| 143 | } | 151 | } |
| 144 | 152 | ||
| 153 | struct yue_stack { | ||
| 154 | int continuation; | ||
| 155 | yue::ast_node* node; | ||
| 156 | int i; | ||
| 157 | std::unique_ptr<std::vector<yue::ast_node*>> children; | ||
| 158 | bool hasSep; | ||
| 159 | }; | ||
| 160 | |||
| 145 | static int yuetoast(lua_State* L) { | 161 | static int yuetoast(lua_State* L) { |
| 146 | size_t size = 0; | 162 | size_t size = 0; |
| 147 | const char* input = luaL_checklstring(L, 1, &size); | 163 | const char* input = luaL_checklstring(L, 1, &size); |
| @@ -154,6 +170,8 @@ static int yuetoast(lua_State* L) { | |||
| 154 | auto info = parser.parse<yue::File_t>({input, size}); | 170 | auto info = parser.parse<yue::File_t>({input, size}); |
| 155 | if (info.node) { | 171 | if (info.node) { |
| 156 | lua_createtable(L, 0, 0); | 172 | lua_createtable(L, 0, 0); |
| 173 | int tableIndex = lua_gettop(L); | ||
| 174 | lua_createtable(L, 0, 0); | ||
| 157 | int cacheIndex = lua_gettop(L); | 175 | int cacheIndex = lua_gettop(L); |
| 158 | auto getName = [&](yue::ast_node* node) { | 176 | auto getName = [&](yue::ast_node* node) { |
| 159 | int id = node->getId(); | 177 | int id = node->getId(); |
| @@ -166,64 +184,108 @@ static int yuetoast(lua_State* L) { | |||
| 166 | lua_rawseti(L, cacheIndex, id); | 184 | lua_rawseti(L, cacheIndex, id); |
| 167 | } | 185 | } |
| 168 | }; | 186 | }; |
| 169 | std::function<void(yue::ast_node*)> visit; | 187 | std::stack<yue_stack> stack; |
| 170 | visit = [&](yue::ast_node* node) { | 188 | auto do_call = [&](yue::ast_node* node) { |
| 171 | int count = 0; | 189 | stack.push({0, node, 0, nullptr, false}); |
| 172 | bool hasSep = false; | 190 | }; |
| 173 | node->visitChild([&](yue::ast_node* child) { | 191 | auto do_return = [&]() { |
| 174 | if (yue::ast_is<yue::Seperator_t>(child)) { | 192 | stack.pop(); |
| 175 | hasSep = true; | 193 | }; |
| 176 | return false; | 194 | do_call(info.node); |
| 177 | } | 195 | while (!stack.empty()) { |
| 178 | count++; | 196 | auto& current = stack.top(); |
| 179 | visit(child); | 197 | int continuation = current.continuation; |
| 180 | return false; | 198 | auto node = current.node; |
| 181 | }); | 199 | switch (continuation) { |
| 182 | switch (count) { | ||
| 183 | case 0: { | 200 | case 0: { |
| 184 | lua_createtable(L, 4, 0); | 201 | if (!current.children) { |
| 185 | getName(node); | 202 | node->visitChild([&](yue::ast_node* child) { |
| 186 | lua_rawseti(L, -2, 1); | 203 | if (yue::ast_is<yue::Seperator_t>(child)) { |
| 187 | lua_pushinteger(L, node->m_begin.m_line); | 204 | current.hasSep = true; |
| 188 | lua_rawseti(L, -2, 2); | 205 | return false; |
| 189 | lua_pushinteger(L, node->m_begin.m_col); | 206 | } |
| 190 | lua_rawseti(L, -2, 3); | 207 | if (!current.children) { |
| 191 | auto str = parser.toString(node); | 208 | current.children = std::make_unique<std::vector<yue::ast_node*>>(); |
| 192 | yue::Utils::trim(str); | 209 | } |
| 193 | lua_pushlstring(L, str.c_str(), str.length()); | 210 | current.children->push_back(child); |
| 194 | lua_rawseti(L, -2, 4); | 211 | return false; |
| 212 | }); | ||
| 213 | } | ||
| 214 | current.i = 0; | ||
| 215 | current.continuation = 1; | ||
| 195 | break; | 216 | break; |
| 196 | } | 217 | } |
| 197 | case 1: { | 218 | case 1: { |
| 198 | if (flattenLevel > 1 || (flattenLevel == 1 && !hasSep)) { | 219 | if (current.children && current.i < static_cast<int>(current.children->size())) { |
| 199 | getName(node); | 220 | do_call(current.children->at(current.i)); |
| 200 | lua_rawseti(L, -2, 1); | 221 | current.continuation = 2; |
| 201 | lua_pushinteger(L, node->m_begin.m_line); | ||
| 202 | lua_rawseti(L, -2, 2); | ||
| 203 | lua_pushinteger(L, node->m_begin.m_col); | ||
| 204 | lua_rawseti(L, -2, 3); | ||
| 205 | break; | 222 | break; |
| 206 | } | 223 | } |
| 224 | current.continuation = 3; | ||
| 225 | break; | ||
| 226 | } | ||
| 227 | case 2: { | ||
| 228 | current.i++; | ||
| 229 | current.continuation = 1; | ||
| 230 | break; | ||
| 207 | } | 231 | } |
| 208 | default: { | 232 | case 3: { |
| 209 | lua_createtable(L, count + 3, 0); | 233 | int count = current.children ? static_cast<int>(current.children->size()) : 0; |
| 210 | getName(node); | 234 | switch (count) { |
| 211 | lua_rawseti(L, -2, 1); | 235 | case 0: { |
| 212 | lua_pushinteger(L, node->m_begin.m_line); | 236 | lua_createtable(L, 4, 0); |
| 213 | lua_rawseti(L, -2, 2); | 237 | getName(node); |
| 214 | lua_pushinteger(L, node->m_begin.m_col); | 238 | lua_rawseti(L, -2, 1); |
| 215 | lua_rawseti(L, -2, 3); | 239 | lua_pushinteger(L, node->m_begin.m_line); |
| 216 | for (int i = count, j = 4; i >= 1; i--, j++) { | 240 | lua_rawseti(L, -2, 2); |
| 217 | lua_pushvalue(L, -1 - i); | 241 | lua_pushinteger(L, node->m_begin.m_col); |
| 218 | lua_rawseti(L, -2, j); | 242 | lua_rawseti(L, -2, 3); |
| 243 | auto str = parser.toString(node); | ||
| 244 | yue::Utils::trim(str); | ||
| 245 | lua_pushlstring(L, str.c_str(), str.length()); | ||
| 246 | lua_rawseti(L, -2, 4); | ||
| 247 | lua_rawseti(L, tableIndex, lua_objlen(L, tableIndex) + 1); | ||
| 248 | break; | ||
| 249 | } | ||
| 250 | case 1: { | ||
| 251 | if (flattenLevel > 1 || (flattenLevel == 1 && !current.hasSep)) { | ||
| 252 | lua_rawgeti(L, tableIndex, 1); | ||
| 253 | getName(node); | ||
| 254 | lua_rawseti(L, -2, 1); | ||
| 255 | lua_pushinteger(L, node->m_begin.m_line); | ||
| 256 | lua_rawseti(L, -2, 2); | ||
| 257 | lua_pushinteger(L, node->m_begin.m_col); | ||
| 258 | lua_rawseti(L, -2, 3); | ||
| 259 | lua_pop(L, 1); | ||
| 260 | break; | ||
| 261 | } | ||
| 262 | } | ||
| 263 | default: { | ||
| 264 | auto len = lua_objlen(L, tableIndex); | ||
| 265 | lua_createtable(L, count + 3, 0); | ||
| 266 | getName(node); | ||
| 267 | lua_rawseti(L, -2, 1); | ||
| 268 | lua_pushinteger(L, node->m_begin.m_line); | ||
| 269 | lua_rawseti(L, -2, 2); | ||
| 270 | lua_pushinteger(L, node->m_begin.m_col); | ||
| 271 | lua_rawseti(L, -2, 3); | ||
| 272 | for (int i = count, j = 4; i >= 1; i--, j++) { | ||
| 273 | lua_rawgeti(L, tableIndex, len); | ||
| 274 | lua_rawseti(L, -2, j); | ||
| 275 | lua_pushnil(L); | ||
| 276 | lua_rawseti(L, tableIndex, len); | ||
| 277 | len--; | ||
| 278 | } | ||
| 279 | lua_rawseti(L, tableIndex, lua_objlen(L, tableIndex) + 1); | ||
| 280 | break; | ||
| 281 | } | ||
| 219 | } | 282 | } |
| 220 | lua_insert(L, -1 - count); | 283 | do_return(); |
| 221 | lua_pop(L, count); | ||
| 222 | break; | 284 | break; |
| 223 | } | 285 | } |
| 224 | } | 286 | } |
| 225 | }; | 287 | } |
| 226 | visit(info.node); | 288 | lua_rawgeti(L, tableIndex, 1); |
| 227 | return 1; | 289 | return 1; |
| 228 | } else { | 290 | } else { |
| 229 | lua_pushnil(L); | 291 | lua_pushnil(L); |
