diff options
| author | Li Jin <dragon-fly@qq.com> | 2023-03-23 09:50:56 +0800 |
|---|---|---|
| committer | Li Jin <dragon-fly@qq.com> | 2023-03-23 09:51:15 +0800 |
| commit | f52f54f953feb6bb36a279c42882d7a744695271 (patch) | |
| tree | e71f1df9ff282adf01938b652ce35894d463ce9d | |
| parent | a359ad7a16966c8955ec29e287b78d6a71dd0030 (diff) | |
| download | yuescript-f52f54f953feb6bb36a279c42882d7a744695271.tar.gz yuescript-f52f54f953feb6bb36a279c42882d7a744695271.tar.bz2 yuescript-f52f54f953feb6bb36a279c42882d7a744695271.zip | |
add yue.check function.
Diffstat (limited to '')
| -rw-r--r-- | src/yuescript/stacktraceplus.h | 2 | ||||
| -rw-r--r-- | src/yuescript/yue_compiler.cpp | 405 | ||||
| -rw-r--r-- | src/yuescript/yue_compiler.h | 22 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.cpp | 63 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.h | 46 | ||||
| -rw-r--r-- | src/yuescript/yuescript.cpp | 151 | ||||
| -rw-r--r-- | src/yuescript/yuescript.h | 7 |
7 files changed, 423 insertions, 273 deletions
diff --git a/src/yuescript/stacktraceplus.h b/src/yuescript/stacktraceplus.h index 83460ef..4b6f370 100644 --- a/src/yuescript/stacktraceplus.h +++ b/src/yuescript/stacktraceplus.h | |||
| @@ -345,7 +345,7 @@ local function getYueLineNumber(fname, line) | |||
| 345 | if source then | 345 | if source then |
| 346 | local current, target = 1, tonumber(line) | 346 | local current, target = 1, tonumber(line) |
| 347 | local findLine = line | 347 | local findLine = line |
| 348 | for lineCode in source:gmatch("([^\n]*)\n") do | 348 | for lineCode in source:gmatch("[^\n\r]*") do |
| 349 | local num = lineCode:match("--%s*(%d+)%s*$") | 349 | local num = lineCode:match("--%s*(%d+)%s*$") |
| 350 | if num then | 350 | if num then |
| 351 | findLine = num | 351 | findLine = num |
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 3a9e584..07c0e70 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
| @@ -52,13 +52,12 @@ namespace yue { | |||
| 52 | 52 | ||
| 53 | #define _DEFER(code, line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto) { code; }) | 53 | #define _DEFER(code, line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto) { code; }) |
| 54 | #define DEFER(code) _DEFER(code, __LINE__) | 54 | #define DEFER(code) _DEFER(code, __LINE__) |
| 55 | #define YUEE(msg, node) throw std::logic_error( \ | 55 | #define YUEE(msg, node) throw CompileError( \ |
| 56 | _info.errorMessage( \ | 56 | "[File] "s + __FILE__ \ |
| 57 | "[File] "s + __FILE__ \ | 57 | + ",\n[Func] "s + __FUNCTION__ \ |
| 58 | + ",\n[Func] "s + __FUNCTION__ \ | 58 | + ",\n[Line] "s + std::to_string(__LINE__) \ |
| 59 | + ",\n[Line] "s + std::to_string(__LINE__) \ | 59 | + ",\n[Error] "s + msg, \ |
| 60 | + ",\n[Error] "s + msg, \ | 60 | node) |
| 61 | node)) | ||
| 62 | 61 | ||
| 63 | typedef std::list<std::string> str_list; | 62 | typedef std::list<std::string> str_list; |
| 64 | 63 | ||
| @@ -73,9 +72,51 @@ static std::unordered_set<std::string> Metamethods = { | |||
| 73 | "close"s // Lua 5.4 | 72 | "close"s // Lua 5.4 |
| 74 | }; | 73 | }; |
| 75 | 74 | ||
| 76 | const std::string_view version = "0.15.28"sv; | 75 | const std::string_view version = "0.15.29"sv; |
| 77 | const std::string_view extension = "yue"sv; | 76 | const std::string_view extension = "yue"sv; |
| 78 | 77 | ||
| 78 | class CompileError : public std::logic_error { | ||
| 79 | public: | ||
| 80 | explicit CompileError(std::string_view msg, const input_range* range) | ||
| 81 | : std::logic_error(std::string(msg)) | ||
| 82 | , line(range->m_begin.m_line) | ||
| 83 | , col(range->m_begin.m_col) { } | ||
| 84 | |||
| 85 | int line; | ||
| 86 | int col; | ||
| 87 | }; | ||
| 88 | |||
| 89 | CompileInfo::CompileInfo( | ||
| 90 | std::string&& codes, | ||
| 91 | std::optional<Error>&& error, | ||
| 92 | std::unique_ptr<GlobalVars>&& globals, | ||
| 93 | std::unique_ptr<Options>&& options, | ||
| 94 | double parseTime, | ||
| 95 | double compileTime) | ||
| 96 | : codes(std::move(codes)) | ||
| 97 | , error(std::move(error)) | ||
| 98 | , globals(std::move(globals)) | ||
| 99 | , options(std::move(options)) | ||
| 100 | , parseTime(parseTime) | ||
| 101 | , compileTime(compileTime) { } | ||
| 102 | |||
| 103 | CompileInfo::CompileInfo(CompileInfo&& other) | ||
| 104 | : codes(std::move(other.codes)) | ||
| 105 | , error(std::move(other.error)) | ||
| 106 | , globals(std::move(other.globals)) | ||
| 107 | , options(std::move(other.options)) | ||
| 108 | , parseTime(other.parseTime) | ||
| 109 | , compileTime(other.compileTime) { } | ||
| 110 | |||
| 111 | void CompileInfo::operator=(CompileInfo&& other) { | ||
| 112 | codes = std::move(other.codes); | ||
| 113 | error = std::move(other.error); | ||
| 114 | globals = std::move(other.globals); | ||
| 115 | options = std::move(other.options); | ||
| 116 | parseTime = other.parseTime; | ||
| 117 | compileTime = other.compileTime; | ||
| 118 | } | ||
| 119 | |||
| 79 | class YueCompilerImpl { | 120 | class YueCompilerImpl { |
| 80 | public: | 121 | public: |
| 81 | #ifndef YUE_NO_MACRO | 122 | #ifndef YUE_NO_MACRO |
| @@ -162,7 +203,7 @@ public: | |||
| 162 | if (exportNode->target.is<Macro_t>()) break; | 203 | if (exportNode->target.is<Macro_t>()) break; |
| 163 | } | 204 | } |
| 164 | default: | 205 | default: |
| 165 | throw std::logic_error(_info.errorMessage("macro exporting module only accepts macro definition, macro importing and macro expansion in place", stmt)); | 206 | throw CompileError("macro exporting module only accepts macro definition, macro importing and macro expansion in place"sv, stmt); |
| 166 | break; | 207 | break; |
| 167 | } | 208 | } |
| 168 | } | 209 | } |
| @@ -200,7 +241,7 @@ public: | |||
| 200 | noLabel = false; | 241 | noLabel = false; |
| 201 | BLOCK_END | 242 | BLOCK_END |
| 202 | if (noLabel) { | 243 | if (noLabel) { |
| 203 | throw std::logic_error(_info.errorMessage("no visible label '"s + gotoNode.label + "' for <goto>"s, gotoNode.ptr->label)); | 244 | throw CompileError("no visible label '"s + gotoNode.label + "' for <goto>"s, gotoNode.ptr->label); |
| 204 | } | 245 | } |
| 205 | } | 246 | } |
| 206 | } | 247 | } |
| @@ -241,12 +282,42 @@ public: | |||
| 241 | } | 282 | } |
| 242 | } | 283 | } |
| 243 | #endif // YUE_NO_MACRO | 284 | #endif // YUE_NO_MACRO |
| 244 | return {std::move(out.back()), Empty, std::move(globals), std::move(options), parseTime, compileTime}; | 285 | return {std::move(out.back()), std::nullopt, std::move(globals), std::move(options), parseTime, compileTime}; |
| 245 | } catch (const std::logic_error& error) { | 286 | } catch (const CompileError& error) { |
| 246 | return {Empty, error.what(), std::move(globals), std::move(options), parseTime, compileTime}; | 287 | auto displayMessage = _info.errorMessage(error.what(), error.line, error.col); |
| 288 | return { | ||
| 289 | std::string(), | ||
| 290 | CompileInfo::Error{ | ||
| 291 | error.what(), | ||
| 292 | error.line, error.col, | ||
| 293 | displayMessage}, | ||
| 294 | std::move(globals), | ||
| 295 | std::move(options), | ||
| 296 | parseTime, compileTime}; | ||
| 247 | } | 297 | } |
| 248 | } else { | 298 | } else { |
| 249 | return {Empty, std::move(_info.error), std::move(globals), std::move(options), parseTime, compileTime}; | 299 | const auto& error = _info.error.value(); |
| 300 | if (!_info.codes) { | ||
| 301 | return { | ||
| 302 | std::string(), | ||
| 303 | CompileInfo::Error{ | ||
| 304 | error.msg, | ||
| 305 | error.line, error.col, | ||
| 306 | ""}, | ||
| 307 | std::move(globals), | ||
| 308 | std::move(options), | ||
| 309 | parseTime, compileTime}; | ||
| 310 | } | ||
| 311 | auto displayMessage = _info.errorMessage(error.msg, error.line, error.col); | ||
| 312 | return { | ||
| 313 | std::string(), | ||
| 314 | CompileInfo::Error{ | ||
| 315 | error.msg, | ||
| 316 | error.line, error.col, | ||
| 317 | displayMessage}, | ||
| 318 | std::move(globals), | ||
| 319 | std::move(options), | ||
| 320 | parseTime, compileTime}; | ||
| 250 | } | 321 | } |
| 251 | } | 322 | } |
| 252 | 323 | ||
| @@ -483,7 +554,7 @@ private: | |||
| 483 | 554 | ||
| 484 | void checkConst(const std::string& name, ast_node* x) const { | 555 | void checkConst(const std::string& name, ast_node* x) const { |
| 485 | if (isConst(name)) { | 556 | if (isConst(name)) { |
| 486 | throw std::logic_error(_info.errorMessage("attempt to assign to const variable '"s + name + '\'', x)); | 557 | throw CompileError("attempt to assign to const variable '"s + name + '\'', x); |
| 487 | } | 558 | } |
| 488 | } | 559 | } |
| 489 | 560 | ||
| @@ -503,7 +574,7 @@ private: | |||
| 503 | } | 574 | } |
| 504 | 575 | ||
| 505 | void addGlobalVar(const std::string& name, ast_node* x) { | 576 | void addGlobalVar(const std::string& name, ast_node* x) { |
| 506 | if (isLocal(name)) throw std::logic_error(_info.errorMessage("can not declare a local variable to be global"sv, x)); | 577 | if (isLocal(name)) throw CompileError("can not declare a local variable to be global"sv, x); |
| 507 | auto& scope = _scopes.back(); | 578 | auto& scope = _scopes.back(); |
| 508 | if (!scope.globals) { | 579 | if (!scope.globals) { |
| 509 | scope.globals = std::make_unique<std::unordered_set<std::string>>(); | 580 | scope.globals = std::make_unique<std::unordered_set<std::string>>(); |
| @@ -1051,7 +1122,7 @@ private: | |||
| 1051 | for (auto exp_ : expList->exprs.objects()) { | 1122 | for (auto exp_ : expList->exprs.objects()) { |
| 1052 | Exp_t* exp = static_cast<Exp_t*>(exp_); | 1123 | Exp_t* exp = static_cast<Exp_t*>(exp_); |
| 1053 | if (!isAssignable(exp)) { | 1124 | if (!isAssignable(exp)) { |
| 1054 | throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, exp)); | 1125 | throw CompileError("left hand expression is not assignable"sv, exp); |
| 1055 | } | 1126 | } |
| 1056 | } | 1127 | } |
| 1057 | } | 1128 | } |
| @@ -1120,7 +1191,7 @@ private: | |||
| 1120 | 1191 | ||
| 1121 | void checkMetamethod(const std::string& name, ast_node* x) { | 1192 | void checkMetamethod(const std::string& name, ast_node* x) { |
| 1122 | if (Metamethods.find(name) == Metamethods.end()) { | 1193 | if (Metamethods.find(name) == Metamethods.end()) { |
| 1123 | throw std::logic_error(_info.errorMessage("invalid metamethod name"sv, x)); | 1194 | throw CompileError("invalid metamethod name"sv, x); |
| 1124 | } | 1195 | } |
| 1125 | int target = getLuaTarget(x); | 1196 | int target = getLuaTarget(x); |
| 1126 | switch (target) { | 1197 | switch (target) { |
| @@ -1128,33 +1199,30 @@ private: | |||
| 1128 | case 502: goto metamethod52; | 1199 | case 502: goto metamethod52; |
| 1129 | case 503: { | 1200 | case 503: { |
| 1130 | if (name == "ipairs"sv) { | 1201 | if (name == "ipairs"sv) { |
| 1131 | throw std::logic_error(_info.errorMessage("metamethod is deprecated since Lua 5.3"sv, x)); | 1202 | throw CompileError("metamethod is deprecated since Lua 5.3"sv, x); |
| 1132 | } | 1203 | } |
| 1133 | goto metamethod53; | 1204 | goto metamethod53; |
| 1134 | } | 1205 | } |
| 1135 | case 504: { | 1206 | case 504: { |
| 1136 | if (name == "ipairs"sv) { | 1207 | if (name == "ipairs"sv) { |
| 1137 | throw std::logic_error(_info.errorMessage("metamethod is not supported since Lua 5.4"sv, x)); | 1208 | throw CompileError("metamethod is not supported since Lua 5.4"sv, x); |
| 1138 | } | 1209 | } |
| 1139 | goto metamethod54; | 1210 | goto metamethod54; |
| 1140 | } | 1211 | } |
| 1141 | } | 1212 | } |
| 1142 | metamethod51: | 1213 | metamethod51: |
| 1143 | if (name == "pairs"sv || name == "ipairs"sv) { | 1214 | if (name == "pairs"sv || name == "ipairs"sv) { |
| 1144 | throw std::logic_error(_info.errorMessage("metamethod is not supported until Lua 5.2"sv, x)); | 1215 | throw CompileError("metamethod is not supported until Lua 5.2"sv, x); |
| 1145 | } | 1216 | } |
| 1146 | metamethod52: | 1217 | metamethod52: |
| 1147 | if (name == "name"sv || name == "idiv"sv || | 1218 | if (name == "name"sv || name == "idiv"sv || name == "band"sv || name == "bor"sv || name == "bxor"sv || name == "bnot"sv || name == "shl"sv || name == "shr"sv) { |
| 1148 | name == "band"sv || name == "bor"sv || | 1219 | throw CompileError("metamethod is not supported until Lua 5.3"sv, x); |
| 1149 | name == "bxor"sv || name == "bnot"sv || | ||
| 1150 | name == "shl"sv || name == "shr"sv) { | ||
| 1151 | throw std::logic_error(_info.errorMessage("metamethod is not supported until Lua 5.3"sv, x)); | ||
| 1152 | } | 1220 | } |
| 1153 | metamethod53: | 1221 | metamethod53: |
| 1154 | if (name == "close"sv) { | 1222 | if (name == "close"sv) { |
| 1155 | throw std::logic_error(_info.errorMessage("metamethod is not supported until Lua 5.4"sv, x)); | 1223 | throw CompileError("metamethod is not supported until Lua 5.4"sv, x); |
| 1156 | } | 1224 | } |
| 1157 | metamethod54: | 1225 | metamethod54: |
| 1158 | return; | 1226 | return; |
| 1159 | } | 1227 | } |
| 1160 | 1228 | ||
| @@ -1236,11 +1304,11 @@ private: | |||
| 1236 | return; | 1304 | return; |
| 1237 | } | 1305 | } |
| 1238 | case id<WhileLine_t>(): { | 1306 | case id<WhileLine_t>(): { |
| 1239 | throw std::logic_error(_info.errorMessage("while-loop line decorator is not supported here"sv, appendix->item.get())); | 1307 | throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get()); |
| 1240 | break; | 1308 | break; |
| 1241 | } | 1309 | } |
| 1242 | case id<CompInner_t>(): { | 1310 | case id<CompInner_t>(): { |
| 1243 | throw std::logic_error(_info.errorMessage("for-loop line decorator is not supported here"sv, appendix->item.get())); | 1311 | throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get()); |
| 1244 | break; | 1312 | break; |
| 1245 | } | 1313 | } |
| 1246 | default: YUEE("AST node mismatch", appendix->item.get()); break; | 1314 | default: YUEE("AST node mismatch", appendix->item.get()); break; |
| @@ -1249,10 +1317,10 @@ private: | |||
| 1249 | auto appendix = statement->appendix->item.get(); | 1317 | auto appendix = statement->appendix->item.get(); |
| 1250 | switch (statement->content->getId()) { | 1318 | switch (statement->content->getId()) { |
| 1251 | case id<Return_t>(): | 1319 | case id<Return_t>(): |
| 1252 | throw std::logic_error(_info.errorMessage("loop line decorator can not be used in a return statement"sv, appendix)); | 1320 | throw CompileError("loop line decorator can not be used in a return statement"sv, appendix); |
| 1253 | break; | 1321 | break; |
| 1254 | case id<BreakLoop_t>(): | 1322 | case id<BreakLoop_t>(): |
| 1255 | throw std::logic_error(_info.errorMessage("loop line decorator can not be used in a break-loop statement"sv, appendix)); | 1323 | throw CompileError("loop line decorator can not be used in a break-loop statement"sv, appendix); |
| 1256 | break; | 1324 | break; |
| 1257 | } | 1325 | } |
| 1258 | } | 1326 | } |
| @@ -1343,7 +1411,7 @@ private: | |||
| 1343 | case id<Goto_t>(): transformGoto(static_cast<Goto_t*>(content), out); break; | 1411 | case id<Goto_t>(): transformGoto(static_cast<Goto_t*>(content), out); break; |
| 1344 | case id<ShortTabAppending_t>(): transformShortTabAppending(static_cast<ShortTabAppending_t*>(content), out); break; | 1412 | case id<ShortTabAppending_t>(): transformShortTabAppending(static_cast<ShortTabAppending_t*>(content), out); break; |
| 1345 | case id<LocalAttrib_t>(): transformLocalAttrib(static_cast<LocalAttrib_t*>(content), out); break; | 1413 | case id<LocalAttrib_t>(): transformLocalAttrib(static_cast<LocalAttrib_t*>(content), out); break; |
| 1346 | case id<PipeBody_t>(): throw std::logic_error(_info.errorMessage("pipe chain must be following a value"sv, x)); break; | 1414 | case id<PipeBody_t>(): throw CompileError("pipe chain must be following a value"sv, x); break; |
| 1347 | case id<ExpListAssign_t>(): { | 1415 | case id<ExpListAssign_t>(): { |
| 1348 | auto expListAssign = static_cast<ExpListAssign_t*>(content); | 1416 | auto expListAssign = static_cast<ExpListAssign_t*>(content); |
| 1349 | if (expListAssign->action) { | 1417 | if (expListAssign->action) { |
| @@ -1388,7 +1456,7 @@ private: | |||
| 1388 | break; | 1456 | break; |
| 1389 | } | 1457 | } |
| 1390 | } | 1458 | } |
| 1391 | throw std::logic_error(_info.errorMessage("unexpected expression"sv, expList)); | 1459 | throw CompileError("unexpected expression"sv, expList); |
| 1392 | } | 1460 | } |
| 1393 | break; | 1461 | break; |
| 1394 | } | 1462 | } |
| @@ -1478,7 +1546,7 @@ private: | |||
| 1478 | BLOCK_END | 1546 | BLOCK_END |
| 1479 | } | 1547 | } |
| 1480 | } else { | 1548 | } else { |
| 1481 | throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, exp)); | 1549 | throw CompileError("left hand expression is not assignable"sv, exp); |
| 1482 | } | 1550 | } |
| 1483 | } | 1551 | } |
| 1484 | return defs; | 1552 | return defs; |
| @@ -1558,7 +1626,7 @@ private: | |||
| 1558 | for (auto& destruct : info.destructures) { | 1626 | for (auto& destruct : info.destructures) { |
| 1559 | for (auto& item : destruct.items) { | 1627 | for (auto& item : destruct.items) { |
| 1560 | if (item.targetVar.empty()) { | 1628 | if (item.targetVar.empty()) { |
| 1561 | throw std::logic_error(_info.errorMessage("can only declare variable as const"sv, item.target)); | 1629 | throw CompileError("can only declare variable as const"sv, item.target); |
| 1562 | } | 1630 | } |
| 1563 | markVarConst(item.targetVar); | 1631 | markVarConst(item.targetVar); |
| 1564 | } | 1632 | } |
| @@ -1580,7 +1648,7 @@ private: | |||
| 1580 | } else { | 1648 | } else { |
| 1581 | _buf << "only one right value expected, got "sv << values.size(); | 1649 | _buf << "only one right value expected, got "sv << values.size(); |
| 1582 | } | 1650 | } |
| 1583 | throw std::logic_error(_info.errorMessage(clearBuf(), values.front())); | 1651 | throw CompileError(clearBuf(), values.front()); |
| 1584 | } | 1652 | } |
| 1585 | bool checkValuesLater = false; | 1653 | bool checkValuesLater = false; |
| 1586 | if (exprs.size() > values.size()) { | 1654 | if (exprs.size() > values.size()) { |
| @@ -1595,7 +1663,7 @@ private: | |||
| 1595 | auto value = singleValueFrom(values.back()); | 1663 | auto value = singleValueFrom(values.back()); |
| 1596 | if (!value) { | 1664 | if (!value) { |
| 1597 | _buf << exprs.size() << " right values expected, got "sv << values.size(); | 1665 | _buf << exprs.size() << " right values expected, got "sv << values.size(); |
| 1598 | throw std::logic_error(_info.errorMessage(clearBuf(), values.front())); | 1666 | throw CompileError(clearBuf(), values.front()); |
| 1599 | } | 1667 | } |
| 1600 | if (auto val = value->item.as<SimpleValue_t>()) { | 1668 | if (auto val = value->item.as<SimpleValue_t>()) { |
| 1601 | switch (val->value->getId()) { | 1669 | switch (val->value->getId()) { |
| @@ -1611,7 +1679,7 @@ private: | |||
| 1611 | auto chainValue = value->item.as<ChainValue_t>(); | 1679 | auto chainValue = value->item.as<ChainValue_t>(); |
| 1612 | if (!chainValue || !ast_is<Invoke_t, InvokeArgs_t>(chainValue->items.back())) { | 1680 | if (!chainValue || !ast_is<Invoke_t, InvokeArgs_t>(chainValue->items.back())) { |
| 1613 | _buf << exprs.size() << " right values expected, got "sv << values.size(); | 1681 | _buf << exprs.size() << " right values expected, got "sv << values.size(); |
| 1614 | throw std::logic_error(_info.errorMessage(clearBuf(), values.front())); | 1682 | throw CompileError(clearBuf(), values.front()); |
| 1615 | } | 1683 | } |
| 1616 | auto newAssign = assign->new_ptr<Assign_t>(); | 1684 | auto newAssign = assign->new_ptr<Assign_t>(); |
| 1617 | newAssign->values.dup(assign->values); | 1685 | newAssign->values.dup(assign->values); |
| @@ -1695,7 +1763,7 @@ private: | |||
| 1695 | tmpChain->items.pop_back(); | 1763 | tmpChain->items.pop_back(); |
| 1696 | if (tmpChain->items.empty()) { | 1764 | if (tmpChain->items.empty()) { |
| 1697 | if (_withVars.empty()) { | 1765 | if (_withVars.empty()) { |
| 1698 | throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x)); | 1766 | throw CompileError("short dot/colon syntax must be called within a with block"sv, x); |
| 1699 | } else { | 1767 | } else { |
| 1700 | args.push_back(_withVars.top()); | 1768 | args.push_back(_withVars.top()); |
| 1701 | } | 1769 | } |
| @@ -1703,7 +1771,7 @@ private: | |||
| 1703 | transformExp(newExp(tmpChain, tmpChain), args, ExpUsage::Closure); | 1771 | transformExp(newExp(tmpChain, tmpChain), args, ExpUsage::Closure); |
| 1704 | } | 1772 | } |
| 1705 | if (vit == values.end()) { | 1773 | if (vit == values.end()) { |
| 1706 | throw std::logic_error(_info.errorMessage("right value missing"sv, values.front())); | 1774 | throw CompileError("right value missing"sv, values.front()); |
| 1707 | } | 1775 | } |
| 1708 | transformAssignItem(*vit, args); | 1776 | transformAssignItem(*vit, args); |
| 1709 | _buf << indent() << globalVar("setmetatable"sv, x) << '(' << join(args, ", "sv) << ')' << nll(x); | 1777 | _buf << indent() << globalVar("setmetatable"sv, x) << '(' << join(args, ", "sv) << ')' << nll(x); |
| @@ -1714,7 +1782,7 @@ private: | |||
| 1714 | tmpChain->items.pop_back(); | 1782 | tmpChain->items.pop_back(); |
| 1715 | if (tmpChain->items.empty()) { | 1783 | if (tmpChain->items.empty()) { |
| 1716 | if (_withVars.empty()) { | 1784 | if (_withVars.empty()) { |
| 1717 | throw std::logic_error(_info.errorMessage("short table appending must be called within a with block"sv, x)); | 1785 | throw CompileError("short table appending must be called within a with block"sv, x); |
| 1718 | } else { | 1786 | } else { |
| 1719 | tmpChain->items.push_back(toAst<Callable_t>(_withVars.top(), chainValue)); | 1787 | tmpChain->items.push_back(toAst<Callable_t>(_withVars.top(), chainValue)); |
| 1720 | } | 1788 | } |
| @@ -1738,7 +1806,7 @@ private: | |||
| 1738 | newAssignment->expList.set(toAst<ExpList_t>(varName + "[#"s + varName + "+1]"s, x)); | 1806 | newAssignment->expList.set(toAst<ExpList_t>(varName + "[#"s + varName + "+1]"s, x)); |
| 1739 | auto assign = x->new_ptr<Assign_t>(); | 1807 | auto assign = x->new_ptr<Assign_t>(); |
| 1740 | if (vit == values.end()) { | 1808 | if (vit == values.end()) { |
| 1741 | throw std::logic_error(_info.errorMessage("right value missing"sv, values.front())); | 1809 | throw CompileError("right value missing"sv, values.front()); |
| 1742 | } | 1810 | } |
| 1743 | assign->values.push_back(*vit); | 1811 | assign->values.push_back(*vit); |
| 1744 | newAssignment->action.set(assign); | 1812 | newAssignment->action.set(assign); |
| @@ -2176,7 +2244,7 @@ private: | |||
| 2176 | switch (node->getId()) { | 2244 | switch (node->getId()) { |
| 2177 | case id<Exp_t>(): { | 2245 | case id<Exp_t>(): { |
| 2178 | auto item = singleValueFrom(node)->item.get(); | 2246 | auto item = singleValueFrom(node)->item.get(); |
| 2179 | if (!item) throw std::logic_error(_info.errorMessage("invalid destructure value"sv, node)); | 2247 | if (!item) throw CompileError("invalid destructure value"sv, node); |
| 2180 | auto tbA = item->getByPath<TableLit_t>(); | 2248 | auto tbA = item->getByPath<TableLit_t>(); |
| 2181 | if (tbA) { | 2249 | if (tbA) { |
| 2182 | tableItems = &tbA->values.objects(); | 2250 | tableItems = &tbA->values.objects(); |
| @@ -2208,7 +2276,7 @@ private: | |||
| 2208 | } | 2276 | } |
| 2209 | default: YUEE("AST node mismatch", node); break; | 2277 | default: YUEE("AST node mismatch", node); break; |
| 2210 | } | 2278 | } |
| 2211 | if (!tableItems) throw std::logic_error(_info.errorMessage("invalid destructure value"sv, node)); | 2279 | if (!tableItems) throw CompileError("invalid destructure value"sv, node); |
| 2212 | std::list<DestructItem> pairs; | 2280 | std::list<DestructItem> pairs; |
| 2213 | int index = 0; | 2281 | int index = 0; |
| 2214 | auto subMetaDestruct = node->new_ptr<TableLit_t>(); | 2282 | auto subMetaDestruct = node->new_ptr<TableLit_t>(); |
| @@ -2223,7 +2291,7 @@ private: | |||
| 2223 | } | 2291 | } |
| 2224 | ++index; | 2292 | ++index; |
| 2225 | if (!isAssignable(static_cast<Exp_t*>(pair))) { | 2293 | if (!isAssignable(static_cast<Exp_t*>(pair))) { |
| 2226 | throw std::logic_error(_info.errorMessage("can't destructure value"sv, pair)); | 2294 | throw CompileError("can't destructure value"sv, pair); |
| 2227 | } | 2295 | } |
| 2228 | auto value = singleValueFrom(pair); | 2296 | auto value = singleValueFrom(pair); |
| 2229 | auto item = value->item.get(); | 2297 | auto item = value->item.get(); |
| @@ -2231,7 +2299,7 @@ private: | |||
| 2231 | auto subPairs = destructFromExp(pair, optional); | 2299 | auto subPairs = destructFromExp(pair, optional); |
| 2232 | if (!subPairs.empty()) { | 2300 | if (!subPairs.empty()) { |
| 2233 | if (defVal) { | 2301 | if (defVal) { |
| 2234 | throw std::logic_error(_info.errorMessage("default value is not supported here"sv, defVal)); | 2302 | throw CompileError("default value is not supported here"sv, defVal); |
| 2235 | } | 2303 | } |
| 2236 | } | 2304 | } |
| 2237 | auto indexItem = toAst<Exp_t>(std::to_string(index), value); | 2305 | auto indexItem = toAst<Exp_t>(std::to_string(index), value); |
| @@ -2298,17 +2366,17 @@ private: | |||
| 2298 | } else if (auto key = np->key.as<String_t>()) { | 2366 | } else if (auto key = np->key.as<String_t>()) { |
| 2299 | keyIndex = newExp(key, np->key).get(); | 2367 | keyIndex = newExp(key, np->key).get(); |
| 2300 | } else { | 2368 | } else { |
| 2301 | throw std::logic_error(_info.errorMessage("unsupported key for destructuring"sv, np)); | 2369 | throw CompileError("unsupported key for destructuring"sv, np); |
| 2302 | } | 2370 | } |
| 2303 | } | 2371 | } |
| 2304 | if (auto exp = np->value.as<Exp_t>()) { | 2372 | if (auto exp = np->value.as<Exp_t>()) { |
| 2305 | if (!isAssignable(exp)) throw std::logic_error(_info.errorMessage("can't do destructure value"sv, exp)); | 2373 | if (!isAssignable(exp)) throw CompileError("can't do destructure value"sv, exp); |
| 2306 | auto item = singleValueFrom(exp)->item.get(); | 2374 | auto item = singleValueFrom(exp)->item.get(); |
| 2307 | if (ast_is<SimpleTable_t>(item) || item->getByPath<TableLit_t>()) { | 2375 | if (ast_is<SimpleTable_t>(item) || item->getByPath<TableLit_t>()) { |
| 2308 | auto subPairs = destructFromExp(exp, optional); | 2376 | auto subPairs = destructFromExp(exp, optional); |
| 2309 | if (!subPairs.empty()) { | 2377 | if (!subPairs.empty()) { |
| 2310 | if (defVal) { | 2378 | if (defVal) { |
| 2311 | throw std::logic_error(_info.errorMessage("default value is not supported here"sv, defVal)); | 2379 | throw CompileError("default value is not supported here"sv, defVal); |
| 2312 | } | 2380 | } |
| 2313 | } | 2381 | } |
| 2314 | for (auto& p : subPairs) { | 2382 | for (auto& p : subPairs) { |
| @@ -2333,7 +2401,7 @@ private: | |||
| 2333 | auto subPairs = destructFromExp(np->value, optional); | 2401 | auto subPairs = destructFromExp(np->value, optional); |
| 2334 | if (!subPairs.empty()) { | 2402 | if (!subPairs.empty()) { |
| 2335 | if (defVal) { | 2403 | if (defVal) { |
| 2336 | throw std::logic_error(_info.errorMessage("default value is not supported here"sv, defVal)); | 2404 | throw CompileError("default value is not supported here"sv, defVal); |
| 2337 | } | 2405 | } |
| 2338 | } | 2406 | } |
| 2339 | for (auto& p : subPairs) { | 2407 | for (auto& p : subPairs) { |
| @@ -2461,13 +2529,13 @@ private: | |||
| 2461 | if (auto ssVal = simpleSingleValueFrom(*j)) { | 2529 | if (auto ssVal = simpleSingleValueFrom(*j)) { |
| 2462 | switch (ssVal->value->getId()) { | 2530 | switch (ssVal->value->getId()) { |
| 2463 | case id<ConstValue_t>(): | 2531 | case id<ConstValue_t>(): |
| 2464 | throw std::logic_error(_info.errorMessage("can not destructure a constant"sv, ssVal->value)); | 2532 | throw CompileError("can not destructure a constant"sv, ssVal->value); |
| 2465 | break; | 2533 | break; |
| 2466 | case id<Num_t>(): | 2534 | case id<Num_t>(): |
| 2467 | throw std::logic_error(_info.errorMessage("can not destructure a number"sv, ssVal->value)); | 2535 | throw CompileError("can not destructure a number"sv, ssVal->value); |
| 2468 | break; | 2536 | break; |
| 2469 | case id<FunLit_t>(): | 2537 | case id<FunLit_t>(): |
| 2470 | throw std::logic_error(_info.errorMessage("can not destructure a function"sv, ssVal->value)); | 2538 | throw CompileError("can not destructure a function"sv, ssVal->value); |
| 2471 | break; | 2539 | break; |
| 2472 | } | 2540 | } |
| 2473 | } | 2541 | } |
| @@ -2613,7 +2681,7 @@ private: | |||
| 2613 | simpleValue->value.set(tab); | 2681 | simpleValue->value.set(tab); |
| 2614 | auto pairs = destructFromExp(newExp(simpleValue, expr), optional); | 2682 | auto pairs = destructFromExp(newExp(simpleValue, expr), optional); |
| 2615 | if (pairs.empty()) { | 2683 | if (pairs.empty()) { |
| 2616 | throw std::logic_error(_info.errorMessage("expect items to be destructured"sv, tab)); | 2684 | throw CompileError("expect items to be destructured"sv, tab); |
| 2617 | } | 2685 | } |
| 2618 | destruct.items = std::move(pairs); | 2686 | destruct.items = std::move(pairs); |
| 2619 | if (!varDefOnly) { | 2687 | if (!varDefOnly) { |
| @@ -2715,17 +2783,17 @@ private: | |||
| 2715 | auto action = assignment->action.get(); | 2783 | auto action = assignment->action.get(); |
| 2716 | switch (action->getId()) { | 2784 | switch (action->getId()) { |
| 2717 | case id<Update_t>(): { | 2785 | case id<Update_t>(): { |
| 2718 | if (expList->exprs.size() > 1) throw std::logic_error(_info.errorMessage("can not apply update to multiple values"sv, expList)); | 2786 | if (expList->exprs.size() > 1) throw CompileError("can not apply update to multiple values"sv, expList); |
| 2719 | auto update = static_cast<Update_t*>(action); | 2787 | auto update = static_cast<Update_t*>(action); |
| 2720 | auto leftExp = static_cast<Exp_t*>(expList->exprs.objects().front()); | 2788 | auto leftExp = static_cast<Exp_t*>(expList->exprs.objects().front()); |
| 2721 | auto leftValue = singleValueFrom(leftExp); | 2789 | auto leftValue = singleValueFrom(leftExp); |
| 2722 | if (!leftValue) throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, leftExp)); | 2790 | if (!leftValue) throw CompileError("left hand expression is not assignable"sv, leftExp); |
| 2723 | auto chain = leftValue->item.as<ChainValue_t>(); | 2791 | auto chain = leftValue->item.as<ChainValue_t>(); |
| 2724 | if (!chain) throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, leftValue)); | 2792 | if (!chain) throw CompileError("left hand expression is not assignable"sv, leftValue); |
| 2725 | BLOCK_START { | 2793 | BLOCK_START { |
| 2726 | auto dot = ast_cast<DotChainItem_t>(chain->items.back()); | 2794 | auto dot = ast_cast<DotChainItem_t>(chain->items.back()); |
| 2727 | if (dot && dot->name.is<Metatable_t>()) { | 2795 | if (dot && dot->name.is<Metatable_t>()) { |
| 2728 | throw std::logic_error(_info.errorMessage("can not apply update to a metatable"sv, leftExp)); | 2796 | throw CompileError("can not apply update to a metatable"sv, leftExp); |
| 2729 | } | 2797 | } |
| 2730 | BREAK_IF(chain->items.size() < 2); | 2798 | BREAK_IF(chain->items.size() < 2); |
| 2731 | if (chain->items.size() == 2) { | 2799 | if (chain->items.size() == 2) { |
| @@ -3060,9 +3128,9 @@ private: | |||
| 3060 | auto unary = static_cast<UnaryExp_t*>(*it); | 3128 | auto unary = static_cast<UnaryExp_t*>(*it); |
| 3061 | auto value = static_cast<Value_t*>(singleUnaryExpFrom(unary) ? unary->expos.back() : nullptr); | 3129 | auto value = static_cast<Value_t*>(singleUnaryExpFrom(unary) ? unary->expos.back() : nullptr); |
| 3062 | if (values.back() == *it && !unary->ops.empty() && usage == ExpUsage::Common) { | 3130 | if (values.back() == *it && !unary->ops.empty() && usage == ExpUsage::Common) { |
| 3063 | throw std::logic_error(_info.errorMessage("unexpected expression"sv, x)); | 3131 | throw CompileError("unexpected expression"sv, x); |
| 3064 | } | 3132 | } |
| 3065 | if (!value) throw std::logic_error(_info.errorMessage("pipe operator must be followed by chain value"sv, *it)); | 3133 | if (!value) throw CompileError("pipe operator must be followed by chain value"sv, *it); |
| 3066 | if (auto chainValue = value->item.as<ChainValue_t>()) { | 3134 | if (auto chainValue = value->item.as<ChainValue_t>()) { |
| 3067 | if (isChainValueCall(chainValue)) { | 3135 | if (isChainValueCall(chainValue)) { |
| 3068 | auto last = chainValue->items.back(); | 3136 | auto last = chainValue->items.back(); |
| @@ -3080,7 +3148,7 @@ private: | |||
| 3080 | args->swap(a, arg); | 3148 | args->swap(a, arg); |
| 3081 | findPlaceHolder = true; | 3149 | findPlaceHolder = true; |
| 3082 | } else { | 3150 | } else { |
| 3083 | throw std::logic_error(_info.errorMessage("pipe placeholder can be used only in one place"sv, a)); | 3151 | throw CompileError("pipe placeholder can be used only in one place"sv, a); |
| 3084 | } | 3152 | } |
| 3085 | } | 3153 | } |
| 3086 | } | 3154 | } |
| @@ -3094,7 +3162,7 @@ private: | |||
| 3094 | } | 3162 | } |
| 3095 | arg.set(newExp(unary, x)); | 3163 | arg.set(newExp(unary, x)); |
| 3096 | } else { | 3164 | } else { |
| 3097 | throw std::logic_error(_info.errorMessage("pipe operator must be followed by chain value"sv, value)); | 3165 | throw CompileError("pipe operator must be followed by chain value"sv, value); |
| 3098 | } | 3166 | } |
| 3099 | } | 3167 | } |
| 3100 | switch (usage) { | 3168 | switch (usage) { |
| @@ -3428,7 +3496,7 @@ private: | |||
| 3428 | --last; | 3496 | --last; |
| 3429 | auto lst = static_cast<Statement_t*>(*last); | 3497 | auto lst = static_cast<Statement_t*>(*last); |
| 3430 | if (lst->appendix) { | 3498 | if (lst->appendix) { |
| 3431 | throw std::logic_error(_info.errorMessage("statement decorator must be placed at the end of pipe chain"sv, lst->appendix.get())); | 3499 | throw CompileError("statement decorator must be placed at the end of pipe chain"sv, lst->appendix.get()); |
| 3432 | } | 3500 | } |
| 3433 | lst->appendix.set(stmt->appendix); | 3501 | lst->appendix.set(stmt->appendix); |
| 3434 | stmt->appendix.set(nullptr); | 3502 | stmt->appendix.set(nullptr); |
| @@ -3441,14 +3509,14 @@ private: | |||
| 3441 | } | 3509 | } |
| 3442 | cond = true; | 3510 | cond = true; |
| 3443 | BLOCK_END | 3511 | BLOCK_END |
| 3444 | if (!cond) throw std::logic_error(_info.errorMessage("pipe chain must be following a value"sv, x)); | 3512 | if (!cond) throw CompileError("pipe chain must be following a value"sv, x); |
| 3445 | stmt->content.set(nullptr); | 3513 | stmt->content.set(nullptr); |
| 3446 | auto next = it; | 3514 | auto next = it; |
| 3447 | ++next; | 3515 | ++next; |
| 3448 | BLOCK_START | 3516 | BLOCK_START |
| 3449 | BREAK_IF(next == nodes.end()); | 3517 | BREAK_IF(next == nodes.end()); |
| 3450 | BREAK_IF(!static_cast<Statement_t*>(*next)->content.as<PipeBody_t>()); | 3518 | BREAK_IF(!static_cast<Statement_t*>(*next)->content.as<PipeBody_t>()); |
| 3451 | throw std::logic_error(_info.errorMessage("indent mismatch in pipe chain"sv, *next)); | 3519 | throw CompileError("indent mismatch in pipe chain"sv, *next); |
| 3452 | BLOCK_END | 3520 | BLOCK_END |
| 3453 | } else if (auto backcall = stmt->content.as<Backcall_t>()) { | 3521 | } else if (auto backcall = stmt->content.as<Backcall_t>()) { |
| 3454 | auto x = *nodes.begin(); | 3522 | auto x = *nodes.begin(); |
| @@ -3496,7 +3564,7 @@ private: | |||
| 3496 | args->swap(a, arg); | 3564 | args->swap(a, arg); |
| 3497 | findPlaceHolder = true; | 3565 | findPlaceHolder = true; |
| 3498 | } else { | 3566 | } else { |
| 3499 | throw std::logic_error(_info.errorMessage("backcall placeholder can be used only in one place"sv, a)); | 3567 | throw CompileError("backcall placeholder can be used only in one place"sv, a); |
| 3500 | } | 3568 | } |
| 3501 | } | 3569 | } |
| 3502 | } | 3570 | } |
| @@ -3663,15 +3731,15 @@ private: | |||
| 3663 | } | 3731 | } |
| 3664 | case ExpUsage::Assignment: { | 3732 | case ExpUsage::Assignment: { |
| 3665 | auto last = lastStatementFrom(block); | 3733 | auto last = lastStatementFrom(block); |
| 3666 | if (!last) throw std::logic_error(_info.errorMessage("block is not assignable"sv, block)); | 3734 | if (!last) throw CompileError("block is not assignable"sv, block); |
| 3667 | if (last->appendix) { | 3735 | if (last->appendix) { |
| 3668 | auto appendix = last->appendix->item.get(); | 3736 | auto appendix = last->appendix->item.get(); |
| 3669 | switch (appendix->getId()) { | 3737 | switch (appendix->getId()) { |
| 3670 | case id<WhileLine_t>(): | 3738 | case id<WhileLine_t>(): |
| 3671 | throw std::logic_error(_info.errorMessage("while-loop line decorator is not supported here"sv, appendix)); | 3739 | throw CompileError("while-loop line decorator is not supported here"sv, appendix); |
| 3672 | break; | 3740 | break; |
| 3673 | case id<CompFor_t>(): | 3741 | case id<CompFor_t>(): |
| 3674 | throw std::logic_error(_info.errorMessage("for-loop line decorator is not supported here"sv, appendix)); | 3742 | throw CompileError("for-loop line decorator is not supported here"sv, appendix); |
| 3675 | break; | 3743 | break; |
| 3676 | } | 3744 | } |
| 3677 | } | 3745 | } |
| @@ -3697,7 +3765,7 @@ private: | |||
| 3697 | static_cast<Statement_t*>(*bLast)->needSep.set(nullptr); | 3765 | static_cast<Statement_t*>(*bLast)->needSep.set(nullptr); |
| 3698 | } | 3766 | } |
| 3699 | } else if (!last->content.is<BreakLoop_t>()) { | 3767 | } else if (!last->content.is<BreakLoop_t>()) { |
| 3700 | throw std::logic_error(_info.errorMessage("expecting assignable statement or break loop"sv, last)); | 3768 | throw CompileError("expecting assignable statement or break loop"sv, last); |
| 3701 | } | 3769 | } |
| 3702 | break; | 3770 | break; |
| 3703 | } | 3771 | } |
| @@ -3750,7 +3818,7 @@ private: | |||
| 3750 | } else if (target.value() == "5.4"sv) { | 3818 | } else if (target.value() == "5.4"sv) { |
| 3751 | return 504; | 3819 | return 504; |
| 3752 | } else { | 3820 | } else { |
| 3753 | throw std::logic_error(_info.errorMessage("get invalid Lua target \""s + target.value() + "\", should be 5.1, 5.2, 5.3 or 5.4"s, x)); | 3821 | throw CompileError("get invalid Lua target \""s + target.value() + "\", should be 5.1, 5.2, 5.3 or 5.4"s, x); |
| 3754 | } | 3822 | } |
| 3755 | } | 3823 | } |
| 3756 | #ifndef YUE_NO_MACRO | 3824 | #ifndef YUE_NO_MACRO |
| @@ -3865,7 +3933,7 @@ private: | |||
| 3865 | 3933 | ||
| 3866 | void transformMacro(Macro_t* macro, str_list& out, bool exporting) { | 3934 | void transformMacro(Macro_t* macro, str_list& out, bool exporting) { |
| 3867 | if (_scopes.size() > 1) { | 3935 | if (_scopes.size() > 1) { |
| 3868 | throw std::logic_error(_info.errorMessage("can not define macro outside the root block"sv, macro)); | 3936 | throw CompileError("can not define macro outside the root block"sv, macro); |
| 3869 | } | 3937 | } |
| 3870 | auto macroName = _parser.toString(macro->name); | 3938 | auto macroName = _parser.toString(macro->name); |
| 3871 | auto argsDef = macro->macroLit->argsDef.get(); | 3939 | auto argsDef = macro->macroLit->argsDef.get(); |
| @@ -3874,7 +3942,7 @@ private: | |||
| 3874 | for (auto def_ : argsDef->definitions.objects()) { | 3942 | for (auto def_ : argsDef->definitions.objects()) { |
| 3875 | auto def = static_cast<FnArgDef_t*>(def_); | 3943 | auto def = static_cast<FnArgDef_t*>(def_); |
| 3876 | if (def->name.is<SelfItem_t>()) { | 3944 | if (def->name.is<SelfItem_t>()) { |
| 3877 | throw std::logic_error(_info.errorMessage("self name is not supported for macro function argument"sv, def->name)); | 3945 | throw CompileError("self name is not supported for macro function argument"sv, def->name); |
| 3878 | } else { | 3946 | } else { |
| 3879 | std::string defVal; | 3947 | std::string defVal; |
| 3880 | if (def->defaultValue) { | 3948 | if (def->defaultValue) { |
| @@ -3904,22 +3972,22 @@ private: | |||
| 3904 | pushOptions(macro->m_begin.m_line - 1); // cur loadstring codes chunk options | 3972 | pushOptions(macro->m_begin.m_line - 1); // cur loadstring codes chunk options |
| 3905 | if (lua_pcall(L, 3, 2, 0) != 0) { // loadstring(codes,chunk,options), cur f err | 3973 | if (lua_pcall(L, 3, 2, 0) != 0) { // loadstring(codes,chunk,options), cur f err |
| 3906 | std::string err = lua_tostring(L, -1); | 3974 | std::string err = lua_tostring(L, -1); |
| 3907 | throw std::logic_error(_info.errorMessage("failed to load macro codes\n"s + err, macro->macroLit)); | 3975 | throw CompileError("failed to load macro codes\n"s + err, macro->macroLit); |
| 3908 | } // cur f err | 3976 | } // cur f err |
| 3909 | if (lua_isnil(L, -2) != 0) { // f == nil, cur f err | 3977 | if (lua_isnil(L, -2) != 0) { // f == nil, cur f err |
| 3910 | std::string err = lua_tostring(L, -1); | 3978 | std::string err = lua_tostring(L, -1); |
| 3911 | throw std::logic_error(_info.errorMessage("failed to load macro codes, at (macro "s + macroName + "): "s + err, macro->macroLit)); | 3979 | throw CompileError("failed to load macro codes, at (macro "s + macroName + "): "s + err, macro->macroLit); |
| 3912 | } | 3980 | } |
| 3913 | lua_pop(L, 1); // cur f | 3981 | lua_pop(L, 1); // cur f |
| 3914 | pushYue("pcall"sv); // cur f pcall | 3982 | pushYue("pcall"sv); // cur f pcall |
| 3915 | lua_insert(L, -2); // cur pcall f | 3983 | lua_insert(L, -2); // cur pcall f |
| 3916 | if (lua_pcall(L, 1, 2, 0) != 0) { // f(), cur success macro | 3984 | if (lua_pcall(L, 1, 2, 0) != 0) { // f(), cur success macro |
| 3917 | std::string err = lua_tostring(L, -1); | 3985 | std::string err = lua_tostring(L, -1); |
| 3918 | throw std::logic_error(_info.errorMessage("failed to generate macro function\n"s + err, macro->macroLit)); | 3986 | throw CompileError("failed to generate macro function\n"s + err, macro->macroLit); |
| 3919 | } // cur success res | 3987 | } // cur success res |
| 3920 | if (lua_toboolean(L, -2) == 0) { | 3988 | if (lua_toboolean(L, -2) == 0) { |
| 3921 | std::string err = lua_tostring(L, -1); | 3989 | std::string err = lua_tostring(L, -1); |
| 3922 | throw std::logic_error(_info.errorMessage("failed to generate macro function\n"s + err, macro->macroLit)); | 3990 | throw CompileError("failed to generate macro function\n"s + err, macro->macroLit); |
| 3923 | } // cur true macro | 3991 | } // cur true macro |
| 3924 | lua_remove(L, -2); // cur macro | 3992 | lua_remove(L, -2); // cur macro |
| 3925 | if (exporting && _config.exporting && !_config.module.empty()) { | 3993 | if (exporting && _config.exporting && !_config.module.empty()) { |
| @@ -3936,7 +4004,7 @@ private: | |||
| 3936 | } | 4004 | } |
| 3937 | #else | 4005 | #else |
| 3938 | void transformMacro(Macro_t* macro, str_list&, bool) { | 4006 | void transformMacro(Macro_t* macro, str_list&, bool) { |
| 3939 | throw std::logic_error(_info.errorMessage("macro feature not supported"sv, macro)); | 4007 | throw CompileError("macro feature not supported"sv, macro)); |
| 3940 | } | 4008 | } |
| 3941 | #endif // YUE_NO_MACRO | 4009 | #endif // YUE_NO_MACRO |
| 3942 | 4010 | ||
| @@ -3944,7 +4012,7 @@ private: | |||
| 3944 | if (!_enableReturn.top()) { | 4012 | if (!_enableReturn.top()) { |
| 3945 | ast_node* target = returnNode->valueList.get(); | 4013 | ast_node* target = returnNode->valueList.get(); |
| 3946 | if (!target) target = returnNode; | 4014 | if (!target) target = returnNode; |
| 3947 | throw std::logic_error(_info.errorMessage("can not mix use of return and export statements in module scope"sv, target)); | 4015 | throw CompileError("can not mix use of return and export statements in module scope"sv, target); |
| 3948 | } | 4016 | } |
| 3949 | if (auto valueList = returnNode->valueList.as<ExpListLow_t>()) { | 4017 | if (auto valueList = returnNode->valueList.as<ExpListLow_t>()) { |
| 3950 | if (valueList->exprs.size() == 1) { | 4018 | if (valueList->exprs.size() == 1) { |
| @@ -4067,7 +4135,7 @@ private: | |||
| 4067 | assignSelf = true; | 4135 | assignSelf = true; |
| 4068 | if (def->op) { | 4136 | if (def->op) { |
| 4069 | if (def->defaultValue) { | 4137 | if (def->defaultValue) { |
| 4070 | throw std::logic_error(_info.errorMessage("argument with default value should not check for existence"sv, def->op)); | 4138 | throw CompileError("argument with default value should not check for existence"sv, def->op); |
| 4071 | } | 4139 | } |
| 4072 | arg.checkExistence = true; | 4140 | arg.checkExistence = true; |
| 4073 | } | 4141 | } |
| @@ -4087,10 +4155,10 @@ private: | |||
| 4087 | } | 4155 | } |
| 4088 | case id<Self_t>(): | 4156 | case id<Self_t>(): |
| 4089 | arg.name = "self"sv; | 4157 | arg.name = "self"sv; |
| 4090 | if (def->op) throw std::logic_error(_info.errorMessage("can only check existence for assigning self field"sv, selfName->name)); | 4158 | if (def->op) throw CompileError("can only check existence for assigning self field"sv, selfName->name); |
| 4091 | break; | 4159 | break; |
| 4092 | default: | 4160 | default: |
| 4093 | throw std::logic_error(_info.errorMessage("invald self expression here"sv, selfName->name)); | 4161 | throw CompileError("invald self expression here"sv, selfName->name); |
| 4094 | break; | 4162 | break; |
| 4095 | } | 4163 | } |
| 4096 | break; | 4164 | break; |
| @@ -4296,7 +4364,7 @@ private: | |||
| 4296 | chainValue->items.pop_back(); | 4364 | chainValue->items.pop_back(); |
| 4297 | if (chainValue->items.empty()) { | 4365 | if (chainValue->items.empty()) { |
| 4298 | if (_withVars.empty()) { | 4366 | if (_withVars.empty()) { |
| 4299 | throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x)); | 4367 | throw CompileError("short dot/colon syntax must be called within a with block"sv, x); |
| 4300 | } | 4368 | } |
| 4301 | chainValue->items.push_back(toAst<Callable_t>(_withVars.top(), x)); | 4369 | chainValue->items.push_back(toAst<Callable_t>(_withVars.top(), x)); |
| 4302 | } | 4370 | } |
| @@ -4434,7 +4502,7 @@ private: | |||
| 4434 | case id<ColonChainItem_t>(): | 4502 | case id<ColonChainItem_t>(): |
| 4435 | case id<Exp_t>(): | 4503 | case id<Exp_t>(): |
| 4436 | if (_withVars.empty()) { | 4504 | if (_withVars.empty()) { |
| 4437 | throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, chainList.front())); | 4505 | throw CompileError("short dot/colon syntax must be called within a with block"sv, chainList.front()); |
| 4438 | } else { | 4506 | } else { |
| 4439 | baseChain->items.push_back(toAst<Callable_t>(_withVars.top(), x)); | 4507 | baseChain->items.push_back(toAst<Callable_t>(_withVars.top(), x)); |
| 4440 | } | 4508 | } |
| @@ -4527,7 +4595,7 @@ private: | |||
| 4527 | auto chain = x->new_ptr<ChainValue_t>(); | 4595 | auto chain = x->new_ptr<ChainValue_t>(); |
| 4528 | if (opIt == chainList.begin() && ast_is<ColonChainItem_t, DotChainItem_t>(x)) { | 4596 | if (opIt == chainList.begin() && ast_is<ColonChainItem_t, DotChainItem_t>(x)) { |
| 4529 | if (_withVars.empty()) { | 4597 | if (_withVars.empty()) { |
| 4530 | throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x)); | 4598 | throw CompileError("short dot/colon syntax must be called within a with block"sv, x); |
| 4531 | } else { | 4599 | } else { |
| 4532 | chain->items.push_back(toAst<Callable_t>(_withVars.top(), x)); | 4600 | chain->items.push_back(toAst<Callable_t>(_withVars.top(), x)); |
| 4533 | } | 4601 | } |
| @@ -4671,7 +4739,7 @@ private: | |||
| 4671 | case id<ColonChainItem_t>(): | 4739 | case id<ColonChainItem_t>(): |
| 4672 | case id<Exp_t>(): | 4740 | case id<Exp_t>(): |
| 4673 | if (_withVars.empty()) { | 4741 | if (_withVars.empty()) { |
| 4674 | throw std::logic_error(_info.errorMessage("short dot/colon and indexing syntax must be called within a with block"sv, x)); | 4742 | throw CompileError("short dot/colon and indexing syntax must be called within a with block"sv, x); |
| 4675 | } else { | 4743 | } else { |
| 4676 | temp.push_back(_withVars.top()); | 4744 | temp.push_back(_withVars.top()); |
| 4677 | } | 4745 | } |
| @@ -4704,7 +4772,7 @@ private: | |||
| 4704 | --next; | 4772 | --next; |
| 4705 | } | 4773 | } |
| 4706 | if (!ast_is<Invoke_t, InvokeArgs_t>(followItem)) { | 4774 | if (!ast_is<Invoke_t, InvokeArgs_t>(followItem)) { |
| 4707 | throw std::logic_error(_info.errorMessage("colon chain item must be followed by invoke arguments"sv, colonItem)); | 4775 | throw CompileError("colon chain item must be followed by invoke arguments"sv, colonItem); |
| 4708 | } | 4776 | } |
| 4709 | if (colonItem->name.is<LuaKeyword_t>()) { | 4777 | if (colonItem->name.is<LuaKeyword_t>()) { |
| 4710 | std::string callVar; | 4778 | std::string callVar; |
| @@ -4843,7 +4911,7 @@ private: | |||
| 4843 | 4911 | ||
| 4844 | void transformMacroInPlace(MacroInPlace_t* macroInPlace) { | 4912 | void transformMacroInPlace(MacroInPlace_t* macroInPlace) { |
| 4845 | #ifdef YUE_NO_MACRO | 4913 | #ifdef YUE_NO_MACRO |
| 4846 | throw std::logic_error(_info.errorMessage("macro feature not supported"sv, macroInPlace)); | 4914 | throw CompileError("macro feature not supported"sv, macroInPlace)); |
| 4847 | #else // YUE_NO_MACRO | 4915 | #else // YUE_NO_MACRO |
| 4848 | auto x = macroInPlace; | 4916 | auto x = macroInPlace; |
| 4849 | pushCurrentModule(); // cur | 4917 | pushCurrentModule(); // cur |
| @@ -4858,22 +4926,22 @@ private: | |||
| 4858 | pushOptions(macroInPlace->m_begin.m_line - 1); // loadstring codes chunk options | 4926 | pushOptions(macroInPlace->m_begin.m_line - 1); // loadstring codes chunk options |
| 4859 | if (lua_pcall(L, 3, 2, 0) != 0) { // loadstring(codes,chunk,options), f err | 4927 | if (lua_pcall(L, 3, 2, 0) != 0) { // loadstring(codes,chunk,options), f err |
| 4860 | std::string err = lua_tostring(L, -1); | 4928 | std::string err = lua_tostring(L, -1); |
| 4861 | throw std::logic_error(_info.errorMessage("failed to load macro codes\n"s + err, x)); | 4929 | throw CompileError("failed to load macro codes\n"s + err, x); |
| 4862 | } // f err | 4930 | } // f err |
| 4863 | if (lua_isnil(L, -2) != 0) { // f == nil, f err | 4931 | if (lua_isnil(L, -2) != 0) { // f == nil, f err |
| 4864 | std::string err = lua_tostring(L, -1); | 4932 | std::string err = lua_tostring(L, -1); |
| 4865 | throw std::logic_error(_info.errorMessage("failed to load macro codes, at (macro in-place): "s + err, x)); | 4933 | throw CompileError("failed to load macro codes, at (macro in-place): "s + err, x); |
| 4866 | } | 4934 | } |
| 4867 | lua_pop(L, 1); // f | 4935 | lua_pop(L, 1); // f |
| 4868 | pushYue("pcall"sv); // f pcall | 4936 | pushYue("pcall"sv); // f pcall |
| 4869 | lua_insert(L, -2); // pcall f | 4937 | lua_insert(L, -2); // pcall f |
| 4870 | if (lua_pcall(L, 1, 2, 0) != 0) { // f(), success macroFunc | 4938 | if (lua_pcall(L, 1, 2, 0) != 0) { // f(), success macroFunc |
| 4871 | std::string err = lua_tostring(L, -1); | 4939 | std::string err = lua_tostring(L, -1); |
| 4872 | throw std::logic_error(_info.errorMessage("failed to generate macro function\n"s + err, x)); | 4940 | throw CompileError("failed to generate macro function\n"s + err, x); |
| 4873 | } // success res | 4941 | } // success res |
| 4874 | if (lua_toboolean(L, -2) == 0) { | 4942 | if (lua_toboolean(L, -2) == 0) { |
| 4875 | std::string err = lua_tostring(L, -1); | 4943 | std::string err = lua_tostring(L, -1); |
| 4876 | throw std::logic_error(_info.errorMessage("failed to generate macro function\n"s + err, x)); | 4944 | throw CompileError("failed to generate macro function\n"s + err, x); |
| 4877 | } // true macroFunc | 4945 | } // true macroFunc |
| 4878 | lua_remove(L, -2); // macroFunc | 4946 | lua_remove(L, -2); // macroFunc |
| 4879 | pushYue("pcall"sv); // macroFunc pcall | 4947 | pushYue("pcall"sv); // macroFunc pcall |
| @@ -4881,11 +4949,11 @@ private: | |||
| 4881 | bool success = lua_pcall(L, 1, 2, 0) == 0; | 4949 | bool success = lua_pcall(L, 1, 2, 0) == 0; |
| 4882 | if (!success) { // err | 4950 | if (!success) { // err |
| 4883 | std::string err = lua_tostring(L, -1); | 4951 | std::string err = lua_tostring(L, -1); |
| 4884 | throw std::logic_error(_info.errorMessage("failed to expand macro: "s + err, x)); | 4952 | throw CompileError("failed to expand macro: "s + err, x); |
| 4885 | } // success err | 4953 | } // success err |
| 4886 | if (lua_toboolean(L, -2) == 0) { | 4954 | if (lua_toboolean(L, -2) == 0) { |
| 4887 | std::string err = lua_tostring(L, -1); | 4955 | std::string err = lua_tostring(L, -1); |
| 4888 | throw std::logic_error(_info.errorMessage("failed to expand macro: "s + err, x)); | 4956 | throw CompileError("failed to expand macro: "s + err, x); |
| 4889 | } | 4957 | } |
| 4890 | #endif // YUE_NO_MACRO | 4958 | #endif // YUE_NO_MACRO |
| 4891 | } | 4959 | } |
| @@ -4908,7 +4976,7 @@ private: | |||
| 4908 | if (!_useModule) { | 4976 | if (!_useModule) { |
| 4909 | auto code = expandBuiltinMacro(macroName, x); | 4977 | auto code = expandBuiltinMacro(macroName, x); |
| 4910 | if (!code.empty()) return {Empty, code, {}}; | 4978 | if (!code.empty()) return {Empty, code, {}}; |
| 4911 | throw std::logic_error(_info.errorMessage("can not resolve macro"sv, x)); | 4979 | throw CompileError("can not resolve macro"sv, x); |
| 4912 | } | 4980 | } |
| 4913 | pushCurrentModule(); // cur | 4981 | pushCurrentModule(); // cur |
| 4914 | int top = lua_gettop(L) - 1; | 4982 | int top = lua_gettop(L) - 1; |
| @@ -4918,7 +4986,7 @@ private: | |||
| 4918 | if (lua_isfunction(L, -1) == 0) { | 4986 | if (lua_isfunction(L, -1) == 0) { |
| 4919 | auto code = expandBuiltinMacro(macroName, x); | 4987 | auto code = expandBuiltinMacro(macroName, x); |
| 4920 | if (!code.empty()) return {Empty, code, {}}; | 4988 | if (!code.empty()) return {Empty, code, {}}; |
| 4921 | throw std::logic_error(_info.errorMessage("can not resolve macro"sv, x)); | 4989 | throw CompileError("can not resolve macro"sv, x); |
| 4922 | } // cur macroFunc | 4990 | } // cur macroFunc |
| 4923 | pushYue("pcall"sv); // cur macroFunc pcall | 4991 | pushYue("pcall"sv); // cur macroFunc pcall |
| 4924 | lua_insert(L, -2); // cur pcall macroFunc | 4992 | lua_insert(L, -2); // cur pcall macroFunc |
| @@ -4981,15 +5049,15 @@ private: | |||
| 4981 | bool success = lua_pcall(L, (args ? static_cast<int>(args->size()) : 0) + 1, 2, 0) == 0; | 5049 | bool success = lua_pcall(L, (args ? static_cast<int>(args->size()) : 0) + 1, 2, 0) == 0; |
| 4982 | if (!success) { // cur err | 5050 | if (!success) { // cur err |
| 4983 | std::string err = lua_tostring(L, -1); | 5051 | std::string err = lua_tostring(L, -1); |
| 4984 | throw std::logic_error(_info.errorMessage("failed to expand macro: "s + err, x)); | 5052 | throw CompileError("failed to expand macro: "s + err, x); |
| 4985 | } // cur success res | 5053 | } // cur success res |
| 4986 | if (lua_toboolean(L, -2) == 0) { | 5054 | if (lua_toboolean(L, -2) == 0) { |
| 4987 | std::string err = lua_tostring(L, -1); | 5055 | std::string err = lua_tostring(L, -1); |
| 4988 | throw std::logic_error(_info.errorMessage("failed to expand macro: "s + err, x)); | 5056 | throw CompileError("failed to expand macro: "s + err, x); |
| 4989 | } | 5057 | } |
| 4990 | lua_remove(L, -2); // cur res | 5058 | lua_remove(L, -2); // cur res |
| 4991 | if (lua_isstring(L, -1) == 0 && lua_istable(L, -1) == 0) { | 5059 | if (lua_isstring(L, -1) == 0 && lua_istable(L, -1) == 0) { |
| 4992 | throw std::logic_error(_info.errorMessage("macro function must return string or table"sv, x)); | 5060 | throw CompileError("macro function must return string or table"sv, x); |
| 4993 | } // cur res | 5061 | } // cur res |
| 4994 | std::string codes; | 5062 | std::string codes; |
| 4995 | std::string type; | 5063 | std::string type; |
| @@ -4999,7 +5067,7 @@ private: | |||
| 4999 | if (lua_isstring(L, -1) != 0) { | 5067 | if (lua_isstring(L, -1) != 0) { |
| 5000 | codes = lua_tostring(L, -1); | 5068 | codes = lua_tostring(L, -1); |
| 5001 | } else { | 5069 | } else { |
| 5002 | throw std::logic_error(_info.errorMessage("macro table must contain field \"code\" of string"sv, x)); | 5070 | throw CompileError("macro table must contain field \"code\" of string"sv, x); |
| 5003 | } | 5071 | } |
| 5004 | lua_pop(L, 1); // cur res | 5072 | lua_pop(L, 1); // cur res |
| 5005 | lua_getfield(L, -1, "type"); // cur res type | 5073 | lua_getfield(L, -1, "type"); // cur res type |
| @@ -5007,7 +5075,7 @@ private: | |||
| 5007 | type = lua_tostring(L, -1); | 5075 | type = lua_tostring(L, -1); |
| 5008 | } | 5076 | } |
| 5009 | if (type != "lua"sv && type != "text"sv) { | 5077 | if (type != "lua"sv && type != "text"sv) { |
| 5010 | throw std::logic_error(_info.errorMessage("macro table must contain field \"type\" of value \"lua\" or \"text\""sv, x)); | 5078 | throw CompileError("macro table must contain field \"type\" of value \"lua\" or \"text\""sv, x); |
| 5011 | } | 5079 | } |
| 5012 | lua_pop(L, 1); // cur res | 5080 | lua_pop(L, 1); // cur res |
| 5013 | lua_getfield(L, -1, "locals"); // cur res locals | 5081 | lua_getfield(L, -1, "locals"); // cur res locals |
| @@ -5016,13 +5084,13 @@ private: | |||
| 5016 | lua_rawgeti(L, -1, i + 1); // cur res locals item | 5084 | lua_rawgeti(L, -1, i + 1); // cur res locals item |
| 5017 | size_t len = 0; | 5085 | size_t len = 0; |
| 5018 | if (lua_isstring(L, -1) == 0) { | 5086 | if (lua_isstring(L, -1) == 0) { |
| 5019 | throw std::logic_error(_info.errorMessage("macro table field \"locals\" must be a table of strings"sv, x)); | 5087 | throw CompileError("macro table field \"locals\" must be a table of strings"sv, x); |
| 5020 | } | 5088 | } |
| 5021 | auto name = lua_tolstring(L, -1, &len); | 5089 | auto name = lua_tolstring(L, -1, &len); |
| 5022 | if (_parser.match<Variable_t>({name, len})) { | 5090 | if (_parser.match<Variable_t>({name, len})) { |
| 5023 | localVars.push_back(std::string(name, len)); | 5091 | localVars.push_back(std::string(name, len)); |
| 5024 | } else { | 5092 | } else { |
| 5025 | throw std::logic_error(_info.errorMessage("macro table field \"locals\" must contain names for local variables, got \""s + std::string(name, len) + '"', x)); | 5093 | throw CompileError("macro table field \"locals\" must contain names for local variables, got \""s + std::string(name, len) + '"', x); |
| 5026 | } | 5094 | } |
| 5027 | lua_pop(L, 1); | 5095 | lua_pop(L, 1); |
| 5028 | } | 5096 | } |
| @@ -5046,14 +5114,14 @@ private: | |||
| 5046 | ParseInfo info; | 5114 | ParseInfo info; |
| 5047 | if (type == "lua"sv) { | 5115 | if (type == "lua"sv) { |
| 5048 | if (!isBlock) { | 5116 | if (!isBlock) { |
| 5049 | throw std::logic_error(_info.errorMessage("lua macro can only be placed where block macro is allowed"sv, x)); | 5117 | throw CompileError("lua macro can only be placed where block macro is allowed"sv, x); |
| 5050 | } | 5118 | } |
| 5051 | auto macroChunk = "=(macro "s + _parser.toString(x->name) + ')'; | 5119 | auto macroChunk = "=(macro "s + _parser.toString(x->name) + ')'; |
| 5052 | int top = lua_gettop(L); | 5120 | int top = lua_gettop(L); |
| 5053 | DEFER(lua_settop(L, top)); | 5121 | DEFER(lua_settop(L, top)); |
| 5054 | if (luaL_loadbuffer(L, codes.c_str(), codes.size(), macroChunk.c_str()) != 0) { | 5122 | if (luaL_loadbuffer(L, codes.c_str(), codes.size(), macroChunk.c_str()) != 0) { |
| 5055 | std::string err = lua_tostring(L, -1); | 5123 | std::string err = lua_tostring(L, -1); |
| 5056 | throw std::logic_error(_info.errorMessage(err, x)); | 5124 | throw CompileError(err, x); |
| 5057 | } | 5125 | } |
| 5058 | if (!codes.empty()) { | 5126 | if (!codes.empty()) { |
| 5059 | if (_config.reserveLineNumber) { | 5127 | if (_config.reserveLineNumber) { |
| @@ -5064,7 +5132,7 @@ private: | |||
| 5064 | return {nullptr, nullptr, std::move(codes), std::move(localVars)}; | 5132 | return {nullptr, nullptr, std::move(codes), std::move(localVars)}; |
| 5065 | } else if (type == "text"sv) { | 5133 | } else if (type == "text"sv) { |
| 5066 | if (!isBlock) { | 5134 | if (!isBlock) { |
| 5067 | throw std::logic_error(_info.errorMessage("text macro can only be placed where block macro is allowed"sv, x)); | 5135 | throw CompileError("text macro can only be placed where block macro is allowed"sv, x); |
| 5068 | } | 5136 | } |
| 5069 | if (!codes.empty()) { | 5137 | if (!codes.empty()) { |
| 5070 | codes.append(_newLine); | 5138 | codes.append(_newLine); |
| @@ -5074,22 +5142,19 @@ private: | |||
| 5074 | if (!codes.empty()) { | 5142 | if (!codes.empty()) { |
| 5075 | if (isBlock) { | 5143 | if (isBlock) { |
| 5076 | info = _parser.parse<BlockEnd_t>(codes); | 5144 | info = _parser.parse<BlockEnd_t>(codes); |
| 5077 | if (!info.node) { | 5145 | if (info.error) { |
| 5078 | info.error = info.error.substr(info.error.find(':') + 2); | 5146 | throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x); |
| 5079 | throw std::logic_error(_info.errorMessage("failed to expand macro as block: "s + info.error, x)); | ||
| 5080 | } | 5147 | } |
| 5081 | } else { | 5148 | } else { |
| 5082 | info = _parser.parse<Exp_t>(codes); | 5149 | info = _parser.parse<Exp_t>(codes); |
| 5083 | if (!info.node && allowBlockMacroReturn) { | 5150 | if (!info.node && allowBlockMacroReturn) { |
| 5084 | info = _parser.parse<BlockEnd_t>(codes); | 5151 | info = _parser.parse<BlockEnd_t>(codes); |
| 5085 | if (!info.node) { | 5152 | if (info.error) { |
| 5086 | info.error = info.error.substr(info.error.find(':') + 2); | 5153 | throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x); |
| 5087 | throw std::logic_error(_info.errorMessage("failed to expand macro as expr or block: "s + info.error, x)); | ||
| 5088 | } | 5154 | } |
| 5089 | isBlock = true; | 5155 | isBlock = true; |
| 5090 | } else if (!info.node) { | 5156 | } else if (info.error) { |
| 5091 | info.error = info.error.substr(info.error.find(':') + 2); | 5157 | throw CompileError("failed to expand macro as expr: "s + info.error.value().msg, x); |
| 5092 | throw std::logic_error(_info.errorMessage("failed to expand macro as expr: "s + info.error, x)); | ||
| 5093 | } | 5158 | } |
| 5094 | } | 5159 | } |
| 5095 | int line = x->m_begin.m_line; | 5160 | int line = x->m_begin.m_line; |
| @@ -5140,18 +5205,18 @@ private: | |||
| 5140 | auto stmt = static_cast<Statement_t*>(stmt_); | 5205 | auto stmt = static_cast<Statement_t*>(stmt_); |
| 5141 | if (auto global = stmt->content.as<Global_t>()) { | 5206 | if (auto global = stmt->content.as<Global_t>()) { |
| 5142 | if (global->item.is<GlobalOp_t>()) { | 5207 | if (global->item.is<GlobalOp_t>()) { |
| 5143 | throw std::logic_error(_info.errorMessage("can not insert global statement with wildcard operator from macro"sv, x)); | 5208 | throw CompileError("can not insert global statement with wildcard operator from macro"sv, x); |
| 5144 | } | 5209 | } |
| 5145 | } else if (auto local = stmt->content.as<Local_t>()) { | 5210 | } else if (auto local = stmt->content.as<Local_t>()) { |
| 5146 | if (local->item.is<LocalFlag_t>()) { | 5211 | if (local->item.is<LocalFlag_t>()) { |
| 5147 | throw std::logic_error(_info.errorMessage("can not insert local statement with wildcard operator from macro"sv, x)); | 5212 | throw CompileError("can not insert local statement with wildcard operator from macro"sv, x); |
| 5148 | } | 5213 | } |
| 5149 | } | 5214 | } |
| 5150 | } | 5215 | } |
| 5151 | } | 5216 | } |
| 5152 | return {info.node, std::move(info.codes), Empty, std::move(localVars)}; | 5217 | return {info.node, std::move(info.codes), Empty, std::move(localVars)}; |
| 5153 | } else { | 5218 | } else { |
| 5154 | if (!isBlock) throw std::logic_error(_info.errorMessage("failed to expand empty macro as expr"sv, x)); | 5219 | if (!isBlock) throw CompileError("failed to expand empty macro as expr"sv, x); |
| 5155 | return {x->new_ptr<Block_t>().get(), std::move(info.codes), Empty, std::move(localVars)}; | 5220 | return {x->new_ptr<Block_t>().get(), std::move(info.codes), Empty, std::move(localVars)}; |
| 5156 | } | 5221 | } |
| 5157 | } | 5222 | } |
| @@ -5205,7 +5270,7 @@ private: | |||
| 5205 | return; | 5270 | return; |
| 5206 | #else | 5271 | #else |
| 5207 | (void)allowBlockMacroReturn; | 5272 | (void)allowBlockMacroReturn; |
| 5208 | throw std::logic_error(_info.errorMessage("macro feature not supported"sv, chainValue)); | 5273 | throw CompileError("macro feature not supported"sv, chainValue)); |
| 5209 | #endif // YUE_NO_MACRO | 5274 | #endif // YUE_NO_MACRO |
| 5210 | } | 5275 | } |
| 5211 | const auto& chainList = chainValue->items.objects(); | 5276 | const auto& chainList = chainValue->items.objects(); |
| @@ -5243,11 +5308,11 @@ private: | |||
| 5243 | } | 5308 | } |
| 5244 | 5309 | ||
| 5245 | void transformSlice(Slice_t* slice, str_list&) { | 5310 | void transformSlice(Slice_t* slice, str_list&) { |
| 5246 | throw std::logic_error(_info.errorMessage("slice syntax not supported here"sv, slice)); | 5311 | throw CompileError("slice syntax not supported here"sv, slice); |
| 5247 | } | 5312 | } |
| 5248 | 5313 | ||
| 5249 | void transform_table_appending_op(TableAppendingOp_t* op, str_list&) { | 5314 | void transform_table_appending_op(TableAppendingOp_t* op, str_list&) { |
| 5250 | throw std::logic_error(_info.errorMessage("table appending syntax not supported here"sv, op)); | 5315 | throw CompileError("table appending syntax not supported here"sv, op); |
| 5251 | } | 5316 | } |
| 5252 | 5317 | ||
| 5253 | void transformInvoke(Invoke_t* invoke, str_list& out) { | 5318 | void transformInvoke(Invoke_t* invoke, str_list& out) { |
| @@ -5270,7 +5335,7 @@ private: | |||
| 5270 | for (auto _op : unary_value->ops.objects()) { | 5335 | for (auto _op : unary_value->ops.objects()) { |
| 5271 | std::string op = _parser.toString(_op); | 5336 | std::string op = _parser.toString(_op); |
| 5272 | if (op == "~"sv && getLuaTarget(_op) < 503) { | 5337 | if (op == "~"sv && getLuaTarget(_op) < 503) { |
| 5273 | throw std::logic_error(_info.errorMessage("bitwise operator is not available when not targeting Lua version 5.3 or higher"sv, _op)); | 5338 | throw CompileError("bitwise operator is not available when not targeting Lua version 5.3 or higher"sv, _op); |
| 5274 | } | 5339 | } |
| 5275 | temp.push_back(op == "not"sv ? op + ' ' : op); | 5340 | temp.push_back(op == "not"sv ? op + ' ' : op); |
| 5276 | } | 5341 | } |
| @@ -5287,7 +5352,7 @@ private: | |||
| 5287 | for (auto _op : unary_exp->ops.objects()) { | 5352 | for (auto _op : unary_exp->ops.objects()) { |
| 5288 | std::string op = _parser.toString(_op); | 5353 | std::string op = _parser.toString(_op); |
| 5289 | if (op == "~"sv && getLuaTarget(_op) < 503) { | 5354 | if (op == "~"sv && getLuaTarget(_op) < 503) { |
| 5290 | throw std::logic_error(_info.errorMessage("bitwise operator is not available when not targeting Lua version 5.3 or higher"sv, _op)); | 5355 | throw CompileError("bitwise operator is not available when not targeting Lua version 5.3 or higher"sv, _op); |
| 5291 | } | 5356 | } |
| 5292 | unary_op.append(op == "not"sv ? op + ' ' : op); | 5357 | unary_op.append(op == "not"sv ? op + ' ' : op); |
| 5293 | } | 5358 | } |
| @@ -5311,7 +5376,7 @@ private: | |||
| 5311 | 5376 | ||
| 5312 | void transformVarArg(VarArg_t* varArg, str_list& out) { | 5377 | void transformVarArg(VarArg_t* varArg, str_list& out) { |
| 5313 | if (_varArgs.empty() || !_varArgs.top().hasVar) { | 5378 | if (_varArgs.empty() || !_varArgs.top().hasVar) { |
| 5314 | throw std::logic_error(_info.errorMessage("cannot use '...' outside a vararg function near '...'"sv, varArg)); | 5379 | throw CompileError("cannot use '...' outside a vararg function near '...'"sv, varArg); |
| 5315 | } | 5380 | } |
| 5316 | _varArgs.top().usedVar = true; | 5381 | _varArgs.top().usedVar = true; |
| 5317 | out.push_back("..."s); | 5382 | out.push_back("..."s); |
| @@ -5385,7 +5450,7 @@ private: | |||
| 5385 | case id<VariablePairDef_t>(): { | 5450 | case id<VariablePairDef_t>(): { |
| 5386 | if (auto pair = ast_cast<VariablePairDef_t>(item)) { | 5451 | if (auto pair = ast_cast<VariablePairDef_t>(item)) { |
| 5387 | if (pair->defVal) { | 5452 | if (pair->defVal) { |
| 5388 | throw std::logic_error(_info.errorMessage("invalid default value here"sv, pair->defVal)); | 5453 | throw CompileError("invalid default value here"sv, pair->defVal); |
| 5389 | } | 5454 | } |
| 5390 | item = pair->pair.get(); | 5455 | item = pair->pair.get(); |
| 5391 | } | 5456 | } |
| @@ -5399,7 +5464,7 @@ private: | |||
| 5399 | case id<NormalPairDef_t>(): { | 5464 | case id<NormalPairDef_t>(): { |
| 5400 | if (auto pair = ast_cast<NormalPairDef_t>(item)) { | 5465 | if (auto pair = ast_cast<NormalPairDef_t>(item)) { |
| 5401 | if (pair->defVal) { | 5466 | if (pair->defVal) { |
| 5402 | throw std::logic_error(_info.errorMessage("invalid default value here"sv, pair->defVal)); | 5467 | throw CompileError("invalid default value here"sv, pair->defVal); |
| 5403 | } | 5468 | } |
| 5404 | item = pair->pair.get(); | 5469 | item = pair->pair.get(); |
| 5405 | } | 5470 | } |
| @@ -5451,7 +5516,7 @@ private: | |||
| 5451 | auto current = item; | 5516 | auto current = item; |
| 5452 | if (auto pair = ast_cast<NormalDef_t>(item)) { | 5517 | if (auto pair = ast_cast<NormalDef_t>(item)) { |
| 5453 | if (pair->defVal) { | 5518 | if (pair->defVal) { |
| 5454 | throw std::logic_error(_info.errorMessage("invalid default value here"sv, pair->defVal)); | 5519 | throw CompileError("invalid default value here"sv, pair->defVal); |
| 5455 | } | 5520 | } |
| 5456 | item = pair->item.get(); | 5521 | item = pair->item.get(); |
| 5457 | } | 5522 | } |
| @@ -5500,7 +5565,7 @@ private: | |||
| 5500 | case id<MetaVariablePairDef_t>(): { | 5565 | case id<MetaVariablePairDef_t>(): { |
| 5501 | if (auto pair = ast_cast<MetaVariablePairDef_t>(item)) { | 5566 | if (auto pair = ast_cast<MetaVariablePairDef_t>(item)) { |
| 5502 | if (pair->defVal) { | 5567 | if (pair->defVal) { |
| 5503 | throw std::logic_error(_info.errorMessage("invalid default value here"sv, pair->defVal)); | 5568 | throw CompileError("invalid default value here"sv, pair->defVal); |
| 5504 | } | 5569 | } |
| 5505 | item = pair->pair.get(); | 5570 | item = pair->pair.get(); |
| 5506 | } | 5571 | } |
| @@ -5514,7 +5579,7 @@ private: | |||
| 5514 | case id<MetaNormalPairDef_t>(): { | 5579 | case id<MetaNormalPairDef_t>(): { |
| 5515 | if (auto pair = ast_cast<MetaNormalPairDef_t>(item)) { | 5580 | if (auto pair = ast_cast<MetaNormalPairDef_t>(item)) { |
| 5516 | if (pair->defVal) { | 5581 | if (pair->defVal) { |
| 5517 | throw std::logic_error(_info.errorMessage("invalid default value here"sv, pair->defVal)); | 5582 | throw CompileError("invalid default value here"sv, pair->defVal); |
| 5518 | } | 5583 | } |
| 5519 | item = pair->pair.get(); | 5584 | item = pair->pair.get(); |
| 5520 | } | 5585 | } |
| @@ -5601,7 +5666,7 @@ private: | |||
| 5601 | case id<VariablePairDef_t>(): { | 5666 | case id<VariablePairDef_t>(): { |
| 5602 | auto pair = static_cast<VariablePairDef_t*>(item); | 5667 | auto pair = static_cast<VariablePairDef_t*>(item); |
| 5603 | if (pair->defVal) { | 5668 | if (pair->defVal) { |
| 5604 | throw std::logic_error(_info.errorMessage("invalid default value"sv, pair->defVal)); | 5669 | throw CompileError("invalid default value"sv, pair->defVal); |
| 5605 | } | 5670 | } |
| 5606 | item = pair->pair.get(); | 5671 | item = pair->pair.get(); |
| 5607 | break; | 5672 | break; |
| @@ -5609,7 +5674,7 @@ private: | |||
| 5609 | case id<NormalPairDef_t>(): { | 5674 | case id<NormalPairDef_t>(): { |
| 5610 | auto pair = static_cast<NormalPairDef_t*>(item); | 5675 | auto pair = static_cast<NormalPairDef_t*>(item); |
| 5611 | if (pair->defVal) { | 5676 | if (pair->defVal) { |
| 5612 | throw std::logic_error(_info.errorMessage("invalid default value"sv, pair->defVal)); | 5677 | throw CompileError("invalid default value"sv, pair->defVal); |
| 5613 | } | 5678 | } |
| 5614 | item = pair->pair.get(); | 5679 | item = pair->pair.get(); |
| 5615 | break; | 5680 | break; |
| @@ -5617,7 +5682,7 @@ private: | |||
| 5617 | case id<MetaVariablePairDef_t>(): { | 5682 | case id<MetaVariablePairDef_t>(): { |
| 5618 | auto pair = static_cast<MetaVariablePairDef_t*>(item); | 5683 | auto pair = static_cast<MetaVariablePairDef_t*>(item); |
| 5619 | if (pair->defVal) { | 5684 | if (pair->defVal) { |
| 5620 | throw std::logic_error(_info.errorMessage("invalid default value"sv, pair->defVal)); | 5685 | throw CompileError("invalid default value"sv, pair->defVal); |
| 5621 | } | 5686 | } |
| 5622 | item = pair->pair.get(); | 5687 | item = pair->pair.get(); |
| 5623 | break; | 5688 | break; |
| @@ -5625,7 +5690,7 @@ private: | |||
| 5625 | case id<MetaNormalPairDef_t>(): { | 5690 | case id<MetaNormalPairDef_t>(): { |
| 5626 | auto pair = static_cast<MetaNormalPairDef_t*>(item); | 5691 | auto pair = static_cast<MetaNormalPairDef_t*>(item); |
| 5627 | if (pair->defVal) { | 5692 | if (pair->defVal) { |
| 5628 | throw std::logic_error(_info.errorMessage("invalid default value"sv, pair->defVal)); | 5693 | throw CompileError("invalid default value"sv, pair->defVal); |
| 5629 | } | 5694 | } |
| 5630 | item = pair->pair.get(); | 5695 | item = pair->pair.get(); |
| 5631 | break; | 5696 | break; |
| @@ -5633,7 +5698,7 @@ private: | |||
| 5633 | case id<NormalDef_t>(): { | 5698 | case id<NormalDef_t>(): { |
| 5634 | auto pair = static_cast<NormalDef_t*>(item); | 5699 | auto pair = static_cast<NormalDef_t*>(item); |
| 5635 | if (pair->defVal) { | 5700 | if (pair->defVal) { |
| 5636 | throw std::logic_error(_info.errorMessage("invalid default value"sv, pair->defVal)); | 5701 | throw CompileError("invalid default value"sv, pair->defVal); |
| 5637 | } | 5702 | } |
| 5638 | item = pair->item.get(); | 5703 | item = pair->item.get(); |
| 5639 | break; | 5704 | break; |
| @@ -5650,7 +5715,7 @@ private: | |||
| 5650 | isMetamethod = true; | 5715 | isMetamethod = true; |
| 5651 | auto mp = static_cast<MetaVariablePair_t*>(item); | 5716 | auto mp = static_cast<MetaVariablePair_t*>(item); |
| 5652 | if (metatableItem) { | 5717 | if (metatableItem) { |
| 5653 | throw std::logic_error(_info.errorMessage("too many metatable declarations"sv, mp->name)); | 5718 | throw CompileError("too many metatable declarations"sv, mp->name); |
| 5654 | } | 5719 | } |
| 5655 | auto name = _parser.toString(mp->name); | 5720 | auto name = _parser.toString(mp->name); |
| 5656 | checkMetamethod(name, mp->name); | 5721 | checkMetamethod(name, mp->name); |
| @@ -5665,7 +5730,7 @@ private: | |||
| 5665 | auto newPair = item->new_ptr<NormalPair_t>(); | 5730 | auto newPair = item->new_ptr<NormalPair_t>(); |
| 5666 | if (mp->key) { | 5731 | if (mp->key) { |
| 5667 | if (metatableItem) { | 5732 | if (metatableItem) { |
| 5668 | throw std::logic_error(_info.errorMessage("too many metatable declarations"sv, mp->key)); | 5733 | throw CompileError("too many metatable declarations"sv, mp->key); |
| 5669 | } | 5734 | } |
| 5670 | switch (mp->key->getId()) { | 5735 | switch (mp->key->getId()) { |
| 5671 | case id<Name_t>(): { | 5736 | case id<Name_t>(): { |
| @@ -5690,7 +5755,7 @@ private: | |||
| 5690 | metatable->pairs.push_back(newPair); | 5755 | metatable->pairs.push_back(newPair); |
| 5691 | } else { | 5756 | } else { |
| 5692 | if (!metatable->pairs.empty()) { | 5757 | if (!metatable->pairs.empty()) { |
| 5693 | throw std::logic_error(_info.errorMessage("too many metatable declarations"sv, mp->value)); | 5758 | throw CompileError("too many metatable declarations"sv, mp->value); |
| 5694 | } | 5759 | } |
| 5695 | metatableItem.set(mp->value); | 5760 | metatableItem.set(mp->value); |
| 5696 | } | 5761 | } |
| @@ -5910,7 +5975,7 @@ private: | |||
| 5910 | auto indexVar = getUnusedName("_index_"sv); | 5975 | auto indexVar = getUnusedName("_index_"sv); |
| 5911 | varAfter.push_back(indexVar); | 5976 | varAfter.push_back(indexVar); |
| 5912 | auto value = singleValueFrom(star_exp->value); | 5977 | auto value = singleValueFrom(star_exp->value); |
| 5913 | if (!value) throw std::logic_error(_info.errorMessage("invalid star syntax"sv, star_exp)); | 5978 | if (!value) throw CompileError("invalid star syntax"sv, star_exp); |
| 5914 | bool endWithSlice = false; | 5979 | bool endWithSlice = false; |
| 5915 | BLOCK_START | 5980 | BLOCK_START |
| 5916 | auto chainValue = value->item.as<ChainValue_t>(); | 5981 | auto chainValue = value->item.as<ChainValue_t>(); |
| @@ -6422,11 +6487,11 @@ private: | |||
| 6422 | void checkOperatorAvailable(const std::string& op, ast_node* node) { | 6487 | void checkOperatorAvailable(const std::string& op, ast_node* node) { |
| 6423 | if (op == "&"sv || op == "~"sv || op == "|"sv || op == ">>"sv || op == "<<"sv) { | 6488 | if (op == "&"sv || op == "~"sv || op == "|"sv || op == ">>"sv || op == "<<"sv) { |
| 6424 | if (getLuaTarget(node) < 503) { | 6489 | if (getLuaTarget(node) < 503) { |
| 6425 | throw std::logic_error(_info.errorMessage("bitwise operator is not available when not targeting Lua version 5.3 or higher"sv, node)); | 6490 | throw CompileError("bitwise operator is not available when not targeting Lua version 5.3 or higher"sv, node); |
| 6426 | } | 6491 | } |
| 6427 | } else if (op == "//"sv) { | 6492 | } else if (op == "//"sv) { |
| 6428 | if (getLuaTarget(node) < 503) { | 6493 | if (getLuaTarget(node) < 503) { |
| 6429 | throw std::logic_error(_info.errorMessage("floor division is not available when not targeting Lua version 5.3 or higher"sv, node)); | 6494 | throw CompileError("floor division is not available when not targeting Lua version 5.3 or higher"sv, node); |
| 6430 | } | 6495 | } |
| 6431 | } | 6496 | } |
| 6432 | } | 6497 | } |
| @@ -6668,7 +6733,7 @@ private: | |||
| 6668 | std::string assignItem; | 6733 | std::string assignItem; |
| 6669 | if (assignable) { | 6734 | if (assignable) { |
| 6670 | if (!isAssignable(assignable)) { | 6735 | if (!isAssignable(assignable)) { |
| 6671 | throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, assignable)); | 6736 | throw CompileError("left hand expression is not assignable"sv, assignable); |
| 6672 | } | 6737 | } |
| 6673 | bool newDefined = false; | 6738 | bool newDefined = false; |
| 6674 | std::tie(className, newDefined) = defineClassVariable(assignable); | 6739 | std::tie(className, newDefined) = defineClassVariable(assignable); |
| @@ -6962,7 +7027,7 @@ private: | |||
| 6962 | if (selfItem) { | 7027 | if (selfItem) { |
| 6963 | type = MemType::Property; | 7028 | type = MemType::Property; |
| 6964 | auto name = ast_cast<SelfName_t>(selfItem->name); | 7029 | auto name = ast_cast<SelfName_t>(selfItem->name); |
| 6965 | if (!name) throw std::logic_error(_info.errorMessage("invalid class poperty name"sv, selfItem->name)); | 7030 | if (!name) throw CompileError("invalid class poperty name"sv, selfItem->name); |
| 6966 | newSuperCall = classVar + ".__parent."s + _parser.toString(name->name); | 7031 | newSuperCall = classVar + ".__parent."s + _parser.toString(name->name); |
| 6967 | } else { | 7032 | } else { |
| 6968 | auto x = keyName; | 7033 | auto x = keyName; |
| @@ -7287,17 +7352,17 @@ private: | |||
| 7287 | void transformExport(Export_t* exportNode, str_list& out) { | 7352 | void transformExport(Export_t* exportNode, str_list& out) { |
| 7288 | auto x = exportNode; | 7353 | auto x = exportNode; |
| 7289 | if (_scopes.size() > 1) { | 7354 | if (_scopes.size() > 1) { |
| 7290 | throw std::logic_error(_info.errorMessage("can not do module export outside the root block"sv, exportNode)); | 7355 | throw CompileError("can not do module export outside the root block"sv, exportNode); |
| 7291 | } | 7356 | } |
| 7292 | if (exportNode->assign) { | 7357 | if (exportNode->assign) { |
| 7293 | auto expList = exportNode->target.to<ExpList_t>(); | 7358 | auto expList = exportNode->target.to<ExpList_t>(); |
| 7294 | if (expList->exprs.size() != exportNode->assign->values.size()) { | 7359 | if (expList->exprs.size() != exportNode->assign->values.size()) { |
| 7295 | throw std::logic_error(_info.errorMessage("left and right expressions must be matched in export statement"sv, x)); | 7360 | throw CompileError("left and right expressions must be matched in export statement"sv, x); |
| 7296 | } | 7361 | } |
| 7297 | for (auto _exp : expList->exprs.objects()) { | 7362 | for (auto _exp : expList->exprs.objects()) { |
| 7298 | auto exp = static_cast<Exp_t*>(_exp); | 7363 | auto exp = static_cast<Exp_t*>(_exp); |
| 7299 | if (!variableFrom(exp) && !exp->getByPath<UnaryExp_t, Value_t, SimpleValue_t, TableLit_t>() && !exp->getByPath<UnaryExp_t, Value_t, SimpleTable_t>()) { | 7364 | if (!variableFrom(exp) && !exp->getByPath<UnaryExp_t, Value_t, SimpleValue_t, TableLit_t>() && !exp->getByPath<UnaryExp_t, Value_t, SimpleTable_t>()) { |
| 7300 | throw std::logic_error(_info.errorMessage("left hand expressions must be variables in export statement"sv, x)); | 7365 | throw CompileError("left hand expressions must be variables in export statement"sv, x); |
| 7301 | } | 7366 | } |
| 7302 | } | 7367 | } |
| 7303 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 7368 | auto assignment = x->new_ptr<ExpListAssign_t>(); |
| @@ -7696,7 +7761,7 @@ private: | |||
| 7696 | case id<MacroName_t>(): | 7761 | case id<MacroName_t>(): |
| 7697 | case id<MacroNamePair_t>(): | 7762 | case id<MacroNamePair_t>(): |
| 7698 | case id<ImportAllMacro_t>(): { | 7763 | case id<ImportAllMacro_t>(): { |
| 7699 | throw std::logic_error(_info.errorMessage("macro feature not supported"sv, item)); | 7764 | throw CompileError("macro feature not supported"sv, item)); |
| 7700 | break; | 7765 | break; |
| 7701 | } | 7766 | } |
| 7702 | #else // YUE_NO_MACRO | 7767 | #else // YUE_NO_MACRO |
| @@ -7712,7 +7777,7 @@ private: | |||
| 7712 | break; | 7777 | break; |
| 7713 | } | 7778 | } |
| 7714 | case id<ImportAllMacro_t>(): | 7779 | case id<ImportAllMacro_t>(): |
| 7715 | if (importAllMacro) throw std::logic_error(_info.errorMessage("import all macro symbol duplicated"sv, item)); | 7780 | if (importAllMacro) throw CompileError("import all macro symbol duplicated"sv, item); |
| 7716 | importAllMacro = true; | 7781 | importAllMacro = true; |
| 7717 | break; | 7782 | break; |
| 7718 | #endif // YUE_NO_MACRO | 7783 | #endif // YUE_NO_MACRO |
| @@ -7740,7 +7805,7 @@ private: | |||
| 7740 | lua_pushlstring(L, moduleName.c_str(), moduleName.size()); // cur find_modulepath moduleName | 7805 | lua_pushlstring(L, moduleName.c_str(), moduleName.size()); // cur find_modulepath moduleName |
| 7741 | if (lua_pcall(L, 1, 2, 0) != 0) { | 7806 | if (lua_pcall(L, 1, 2, 0) != 0) { |
| 7742 | std::string err = lua_tostring(L, -1); | 7807 | std::string err = lua_tostring(L, -1); |
| 7743 | throw std::logic_error(_info.errorMessage("failed to resolve module path\n"s + err, x)); | 7808 | throw CompileError("failed to resolve module path\n"s + err, x); |
| 7744 | } | 7809 | } |
| 7745 | if (lua_isnil(L, -2) != 0) { | 7810 | if (lua_isnil(L, -2) != 0) { |
| 7746 | str_list files; | 7811 | str_list files; |
| @@ -7752,7 +7817,7 @@ private: | |||
| 7752 | lua_pop(L, 1); | 7817 | lua_pop(L, 1); |
| 7753 | } | 7818 | } |
| 7754 | } | 7819 | } |
| 7755 | throw std::logic_error(_info.errorMessage("module '"s + moduleName + "\' not found:\n\t"s + join(files, "\n\t"sv), x)); | 7820 | throw CompileError("module '"s + moduleName + "\' not found:\n\t"s + join(files, "\n\t"sv), x); |
| 7756 | } | 7821 | } |
| 7757 | lua_pop(L, 1); | 7822 | lua_pop(L, 1); |
| 7758 | std::string moduleFullName = lua_tostring(L, -1); | 7823 | std::string moduleFullName = lua_tostring(L, -1); |
| @@ -7762,10 +7827,10 @@ private: | |||
| 7762 | lua_pushlstring(L, moduleFullName.c_str(), moduleFullName.size()); // cur load_text moduleFullName | 7827 | lua_pushlstring(L, moduleFullName.c_str(), moduleFullName.size()); // cur load_text moduleFullName |
| 7763 | if (lua_pcall(L, 1, 1, 0) != 0) { | 7828 | if (lua_pcall(L, 1, 1, 0) != 0) { |
| 7764 | std::string err = lua_tostring(L, -1); | 7829 | std::string err = lua_tostring(L, -1); |
| 7765 | throw std::logic_error(_info.errorMessage("failed to read module file\n"s + err, x)); | 7830 | throw CompileError("failed to read module file\n"s + err, x); |
| 7766 | } // cur text | 7831 | } // cur text |
| 7767 | if (lua_isnil(L, -1) != 0) { | 7832 | if (lua_isnil(L, -1) != 0) { |
| 7768 | throw std::logic_error(_info.errorMessage("failed to get module text"sv, x)); | 7833 | throw CompileError("failed to get module text"sv, x); |
| 7769 | } // cur text | 7834 | } // cur text |
| 7770 | std::string text = lua_tostring(L, -1); | 7835 | std::string text = lua_tostring(L, -1); |
| 7771 | auto compiler = YueCompilerImpl(L, _luaOpen, false); | 7836 | auto compiler = YueCompilerImpl(L, _luaOpen, false); |
| @@ -7777,8 +7842,8 @@ private: | |||
| 7777 | config.module = moduleFullName; | 7842 | config.module = moduleFullName; |
| 7778 | config.exporting = true; | 7843 | config.exporting = true; |
| 7779 | auto result = compiler.compile(text, config); | 7844 | auto result = compiler.compile(text, config); |
| 7780 | if (result.codes.empty() && !result.error.empty()) { | 7845 | if (result.error) { |
| 7781 | throw std::logic_error(_info.errorMessage("failed to compile module '"s + moduleName + "\': "s + result.error, x)); | 7846 | throw CompileError("failed to compile module '"s + moduleName + "\': "s + result.error.value().msg, x); |
| 7782 | } | 7847 | } |
| 7783 | lua_pop(L, 1); // cur | 7848 | lua_pop(L, 1); // cur |
| 7784 | } | 7849 | } |
| @@ -7798,7 +7863,7 @@ private: | |||
| 7798 | } | 7863 | } |
| 7799 | #else // YUE_NO_MACRO | 7864 | #else // YUE_NO_MACRO |
| 7800 | if (importAllMacro) { | 7865 | if (importAllMacro) { |
| 7801 | throw std::logic_error(_info.errorMessage("macro feature not supported"sv, import->target)); | 7866 | throw CompileError("macro feature not supported"sv, import->target)); |
| 7802 | } | 7867 | } |
| 7803 | #endif // YUE_NO_MACRO | 7868 | #endif // YUE_NO_MACRO |
| 7804 | if (newTab->items.empty()) { | 7869 | if (newTab->items.empty()) { |
| @@ -8034,10 +8099,12 @@ private: | |||
| 8034 | pushScope(); | 8099 | pushScope(); |
| 8035 | extraScope = true; | 8100 | extraScope = true; |
| 8036 | } | 8101 | } |
| 8102 | auto typeVar = getUnusedName("_type_"); | ||
| 8103 | forceAddToScope(typeVar); | ||
| 8037 | tabCheckVar = getUnusedName("_tab_"); | 8104 | tabCheckVar = getUnusedName("_tab_"); |
| 8038 | forceAddToScope(tabCheckVar); | 8105 | forceAddToScope(tabCheckVar); |
| 8039 | temp.push_back(indent() + "local "s + tabCheckVar + " = "s + globalVar("type", branch) + '(' + objVar + ')' + nll(branch)); | 8106 | temp.push_back(indent() + "local "s + typeVar + " = "s + globalVar("type", branch) + '(' + objVar + ')' + nll(branch)); |
| 8040 | temp.push_back(indent() + tabCheckVar + " = \"table\" == "s + tabCheckVar + " or \"userdata\" == "s + tabCheckVar + nll(branch)); | 8107 | temp.push_back(indent() + "local "s + tabCheckVar + " = \"table\" == "s + typeVar + " or \"userdata\" == "s + typeVar + nll(branch)); |
| 8041 | } | 8108 | } |
| 8042 | std::string matchVar; | 8109 | std::string matchVar; |
| 8043 | bool lastBranch = branches.back() == branch_ && !switchNode->lastBranch; | 8110 | bool lastBranch = branches.back() == branch_ && !switchNode->lastBranch; |
| @@ -8199,7 +8266,7 @@ private: | |||
| 8199 | } else { | 8266 | } else { |
| 8200 | _buf << "only one right value expected, got "sv << x->assign->values.size(); | 8267 | _buf << "only one right value expected, got "sv << x->assign->values.size(); |
| 8201 | } | 8268 | } |
| 8202 | throw std::logic_error(_info.errorMessage(clearBuf(), x->assign->values.front())); | 8269 | throw CompileError(clearBuf(), x->assign->values.front()); |
| 8203 | } | 8270 | } |
| 8204 | auto listA = x->new_ptr<NameList_t>(); | 8271 | auto listA = x->new_ptr<NameList_t>(); |
| 8205 | auto assignA = x->new_ptr<Assign_t>(); | 8272 | auto assignA = x->new_ptr<Assign_t>(); |
| @@ -8257,7 +8324,7 @@ private: | |||
| 8257 | } | 8324 | } |
| 8258 | } else { | 8325 | } else { |
| 8259 | if (localAttrib->attrib.is<CloseAttrib_t>()) { | 8326 | if (localAttrib->attrib.is<CloseAttrib_t>()) { |
| 8260 | throw std::logic_error(_info.errorMessage("close attribute is not available when not targeting Lua version 5.4 or higher"sv, x)); | 8327 | throw CompileError("close attribute is not available when not targeting Lua version 5.4 or higher"sv, x); |
| 8261 | } | 8328 | } |
| 8262 | for (auto& var : vars) { | 8329 | for (auto& var : vars) { |
| 8263 | markVarConst(var); | 8330 | markVarConst(var); |
| @@ -8281,13 +8348,13 @@ private: | |||
| 8281 | void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) { | 8348 | void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) { |
| 8282 | auto keyword = _parser.toString(breakLoop); | 8349 | auto keyword = _parser.toString(breakLoop); |
| 8283 | if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) { | 8350 | if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) { |
| 8284 | throw std::logic_error(_info.errorMessage(keyword + " is not inside a loop"s, breakLoop)); | 8351 | throw CompileError(keyword + " is not inside a loop"s, breakLoop); |
| 8285 | } | 8352 | } |
| 8286 | if (keyword == "break"sv) { | 8353 | if (keyword == "break"sv) { |
| 8287 | out.push_back(indent() + keyword + nll(breakLoop)); | 8354 | out.push_back(indent() + keyword + nll(breakLoop)); |
| 8288 | return; | 8355 | return; |
| 8289 | } | 8356 | } |
| 8290 | if (_continueVars.empty()) throw std::logic_error(_info.errorMessage("continue is not inside a loop"sv, breakLoop)); | 8357 | if (_continueVars.empty()) throw CompileError("continue is not inside a loop"sv, breakLoop); |
| 8291 | str_list temp; | 8358 | str_list temp; |
| 8292 | auto& item = _continueVars.top(); | 8359 | auto& item = _continueVars.top(); |
| 8293 | if (item.condAssign) { | 8360 | if (item.condAssign) { |
| @@ -8308,7 +8375,7 @@ private: | |||
| 8308 | 8375 | ||
| 8309 | void transformLabel(Label_t* label, str_list& out) { | 8376 | void transformLabel(Label_t* label, str_list& out) { |
| 8310 | if (getLuaTarget(label) < 502) { | 8377 | if (getLuaTarget(label) < 502) { |
| 8311 | throw std::logic_error(_info.errorMessage("label statement is not available when not targeting Lua version 5.2 or higher"sv, label)); | 8378 | throw CompileError("label statement is not available when not targeting Lua version 5.2 or higher"sv, label); |
| 8312 | } | 8379 | } |
| 8313 | auto labelStr = _parser.toString(label->label); | 8380 | auto labelStr = _parser.toString(label->label); |
| 8314 | int currentScope = _gotoScopes.top(); | 8381 | int currentScope = _gotoScopes.top(); |
| @@ -8321,7 +8388,7 @@ private: | |||
| 8321 | } | 8388 | } |
| 8322 | auto& scope = _labels[currentScope].value(); | 8389 | auto& scope = _labels[currentScope].value(); |
| 8323 | if (auto it = scope.find(labelStr); it != scope.end()) { | 8390 | if (auto it = scope.find(labelStr); it != scope.end()) { |
| 8324 | throw std::logic_error(_info.errorMessage("label '"s + labelStr + "' already defined at line "s + std::to_string(it->second.line), label)); | 8391 | throw CompileError("label '"s + labelStr + "' already defined at line "s + std::to_string(it->second.line), label); |
| 8325 | } | 8392 | } |
| 8326 | scope[labelStr] = {label->m_begin.m_line, static_cast<int>(_scopes.size())}; | 8393 | scope[labelStr] = {label->m_begin.m_line, static_cast<int>(_scopes.size())}; |
| 8327 | out.push_back(indent() + "::"s + labelStr + "::"s + nll(label)); | 8394 | out.push_back(indent() + "::"s + labelStr + "::"s + nll(label)); |
| @@ -8329,7 +8396,7 @@ private: | |||
| 8329 | 8396 | ||
| 8330 | void transformGoto(Goto_t* gotoNode, str_list& out) { | 8397 | void transformGoto(Goto_t* gotoNode, str_list& out) { |
| 8331 | if (getLuaTarget(gotoNode) < 502) { | 8398 | if (getLuaTarget(gotoNode) < 502) { |
| 8332 | throw std::logic_error(_info.errorMessage("goto statement is not available when not targeting Lua version 5.2 or higher"sv, gotoNode)); | 8399 | throw CompileError("goto statement is not available when not targeting Lua version 5.2 or higher"sv, gotoNode); |
| 8333 | } | 8400 | } |
| 8334 | auto labelStr = _parser.toString(gotoNode->label); | 8401 | auto labelStr = _parser.toString(gotoNode->label); |
| 8335 | gotos.push_back({gotoNode, labelStr, _gotoScopes.top(), static_cast<int>(_scopes.size())}); | 8402 | gotos.push_back({gotoNode, labelStr, _gotoScopes.top(), static_cast<int>(_scopes.size())}); |
| @@ -8338,7 +8405,7 @@ private: | |||
| 8338 | 8405 | ||
| 8339 | void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) { | 8406 | void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) { |
| 8340 | if (_withVars.empty()) { | 8407 | if (_withVars.empty()) { |
| 8341 | throw std::logic_error(_info.errorMessage("short table appending syntax must be called within a with block"sv, tab)); | 8408 | throw CompileError("short table appending syntax must be called within a with block"sv, tab); |
| 8342 | } | 8409 | } |
| 8343 | auto assignment = toAst<ExpListAssign_t>(_withVars.top() + "[]=nil"s, tab); | 8410 | auto assignment = toAst<ExpListAssign_t>(_withVars.top() + "[]=nil"s, tab); |
| 8344 | assignment->action.set(tab->assign); | 8411 | assignment->action.set(tab->assign); |
| @@ -8349,7 +8416,7 @@ private: | |||
| 8349 | auto x = chainAssign; | 8416 | auto x = chainAssign; |
| 8350 | auto value = chainAssign->assign->values.front(); | 8417 | auto value = chainAssign->assign->values.front(); |
| 8351 | if (chainAssign->assign->values.size() != 1) { | 8418 | if (chainAssign->assign->values.size() != 1) { |
| 8352 | throw std::logic_error(_info.errorMessage("only one right value expected"sv, value)); | 8419 | throw CompileError("only one right value expected"sv, value); |
| 8353 | } | 8420 | } |
| 8354 | str_list temp; | 8421 | str_list temp; |
| 8355 | bool constVal = false; | 8422 | bool constVal = false; |
diff --git a/src/yuescript/yue_compiler.h b/src/yuescript/yue_compiler.h index a5d33cc..860ddfb 100644 --- a/src/yuescript/yue_compiler.h +++ b/src/yuescript/yue_compiler.h | |||
| @@ -11,6 +11,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI | |||
| 11 | #include <functional> | 11 | #include <functional> |
| 12 | #include <list> | 12 | #include <list> |
| 13 | #include <memory> | 13 | #include <memory> |
| 14 | #include <optional> | ||
| 14 | #include <string> | 15 | #include <string> |
| 15 | #include <string_view> | 16 | #include <string_view> |
| 16 | #include <tuple> | 17 | #include <tuple> |
| @@ -30,7 +31,7 @@ struct YueConfig { | |||
| 30 | bool reserveLineNumber = true; | 31 | bool reserveLineNumber = true; |
| 31 | bool useSpaceOverTab = false; | 32 | bool useSpaceOverTab = false; |
| 32 | bool reserveComment = false; | 33 | bool reserveComment = false; |
| 33 | 34 | // internal options | |
| 34 | bool exporting = false; | 35 | bool exporting = false; |
| 35 | bool profiling = false; | 36 | bool profiling = false; |
| 36 | int lineOffset = 0; | 37 | int lineOffset = 0; |
| @@ -48,11 +49,28 @@ using GlobalVars = std::vector<GlobalVar>; | |||
| 48 | 49 | ||
| 49 | struct CompileInfo { | 50 | struct CompileInfo { |
| 50 | std::string codes; | 51 | std::string codes; |
| 51 | std::string error; | 52 | struct Error { |
| 53 | std::string msg; | ||
| 54 | int line; | ||
| 55 | int col; | ||
| 56 | std::string displayMessage; | ||
| 57 | }; | ||
| 58 | std::optional<Error> error; | ||
| 52 | std::unique_ptr<GlobalVars> globals; | 59 | std::unique_ptr<GlobalVars> globals; |
| 53 | std::unique_ptr<Options> options; | 60 | std::unique_ptr<Options> options; |
| 54 | double parseTime; | 61 | double parseTime; |
| 55 | double compileTime; | 62 | double compileTime; |
| 63 | |||
| 64 | CompileInfo() { } | ||
| 65 | CompileInfo( | ||
| 66 | std::string&& codes, | ||
| 67 | std::optional<Error>&& error, | ||
| 68 | std::unique_ptr<GlobalVars>&& globals, | ||
| 69 | std::unique_ptr<Options>&& options, | ||
| 70 | double parseTime, | ||
| 71 | double compileTime); | ||
| 72 | CompileInfo(CompileInfo&& other); | ||
| 73 | void operator=(CompileInfo&& other); | ||
| 56 | }; | 74 | }; |
| 57 | 75 | ||
| 58 | class YueCompilerImpl; | 76 | class YueCompilerImpl; |
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index d8fdc28..f215ee4 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp | |||
| @@ -30,6 +30,17 @@ std::unordered_set<std::string> Keywords = { | |||
| 30 | "try"s, "unless"s, "using"s, "when"s, "with"s // Yue keywords | 30 | "try"s, "unless"s, "using"s, "when"s, "with"s // Yue keywords |
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | class ParserError : public std::logic_error { | ||
| 34 | public: | ||
| 35 | explicit ParserError(std::string_view msg, const pos* begin) | ||
| 36 | : std::logic_error(std::string(msg)) | ||
| 37 | , line(begin->m_line) | ||
| 38 | , col(begin->m_col) { } | ||
| 39 | |||
| 40 | int line; | ||
| 41 | int col; | ||
| 42 | }; | ||
| 43 | |||
| 33 | // clang-format off | 44 | // clang-format off |
| 34 | YueParser::YueParser() { | 45 | YueParser::YueParser() { |
| 35 | plain_space = *set(" \t"); | 46 | plain_space = *set(" \t"); |
| @@ -78,7 +89,7 @@ YueParser::YueParser() { | |||
| 78 | Seperator = true_(); | 89 | Seperator = true_(); |
| 79 | 90 | ||
| 80 | empty_block_error = pl::user(true_(), [](const item_t& item) { | 91 | empty_block_error = pl::user(true_(), [](const item_t& item) { |
| 81 | throw ParserError("must be followed by a statement or an indented block", *item.begin, *item.end); | 92 | throw ParserError("must be followed by a statement or an indented block"sv, item.begin); |
| 82 | return false; | 93 | return false; |
| 83 | }); | 94 | }); |
| 84 | 95 | ||
| @@ -489,7 +500,7 @@ YueParser::YueParser() { | |||
| 489 | st->expLevel++; | 500 | st->expLevel++; |
| 490 | const int max_exp_level = 100; | 501 | const int max_exp_level = 100; |
| 491 | if (st->expLevel > max_exp_level) { | 502 | if (st->expLevel > max_exp_level) { |
| 492 | throw ParserError("nesting expressions exceeds 100 levels", *item.begin, *item.end); | 503 | throw ParserError("nesting expressions exceeds 100 levels"sv, item.begin); |
| 493 | } | 504 | } |
| 494 | return true; | 505 | return true; |
| 495 | }); | 506 | }); |
| @@ -658,10 +669,10 @@ YueParser::YueParser() { | |||
| 658 | }) >> (pl::user(space >> ExportDefault >> space >> Exp, [](const item_t& item) { | 669 | }) >> (pl::user(space >> ExportDefault >> space >> Exp, [](const item_t& item) { |
| 659 | State* st = reinterpret_cast<State*>(item.user_data); | 670 | State* st = reinterpret_cast<State*>(item.user_data); |
| 660 | if (st->exportDefault) { | 671 | if (st->exportDefault) { |
| 661 | throw ParserError("export default has already been declared", *item.begin, *item.end); | 672 | throw ParserError("export default has already been declared"sv, item.begin); |
| 662 | } | 673 | } |
| 663 | if (st->exportCount > 1) { | 674 | if (st->exportCount > 1) { |
| 664 | throw ParserError("there are items already being exported", *item.begin, *item.end); | 675 | throw ParserError("there are items already being exported"sv, item.begin); |
| 665 | } | 676 | } |
| 666 | st->exportDefault = true; | 677 | st->exportDefault = true; |
| 667 | return true; | 678 | return true; |
| @@ -669,7 +680,7 @@ YueParser::YueParser() { | |||
| 669 | | (not_(space >> ExportDefault) >> pl::user(true_(), [](const item_t& item) { | 680 | | (not_(space >> ExportDefault) >> pl::user(true_(), [](const item_t& item) { |
| 670 | State* st = reinterpret_cast<State*>(item.user_data); | 681 | State* st = reinterpret_cast<State*>(item.user_data); |
| 671 | if (st->exportDefault && st->exportCount > 1) { | 682 | if (st->exportDefault && st->exportCount > 1) { |
| 672 | throw ParserError("can not export any more items when 'export default' is declared", *item.begin, *item.end); | 683 | throw ParserError("can not export any more items when 'export default' is declared"sv, item.begin); |
| 673 | } | 684 | } |
| 674 | return true; | 685 | return true; |
| 675 | }) >> space >> ExpList >> -(space >> Assign)) | 686 | }) >> space >> ExpList >> -(space >> Assign)) |
| @@ -762,7 +773,7 @@ YueParser::YueParser() { | |||
| 762 | ) | arg_table_block; | 773 | ) | arg_table_block; |
| 763 | 774 | ||
| 764 | leading_spaces_error = pl::user(+space_one >> '(' >> space >> Exp >> +(space >> ',' >> space >> Exp) >> space >> ')', [](const item_t& item) { | 775 | leading_spaces_error = pl::user(+space_one >> '(' >> space >> Exp >> +(space >> ',' >> space >> Exp) >> space >> ')', [](const item_t& item) { |
| 765 | throw ParserError("write invoke arguments in parentheses without leading spaces or just leading spaces without parentheses", *item.begin, *item.end); | 776 | throw ParserError("write invoke arguments in parentheses without leading spaces or just leading spaces without parentheses"sv, item.begin); |
| 766 | return false; | 777 | return false; |
| 767 | }); | 778 | }); |
| 768 | 779 | ||
| @@ -776,12 +787,12 @@ YueParser::YueParser() { | |||
| 776 | ConstValue = (expr("nil") | "true" | "false") >> not_alpha_num; | 787 | ConstValue = (expr("nil") | "true" | "false") >> not_alpha_num; |
| 777 | 788 | ||
| 778 | braces_expression_error = pl::user(true_(), [](const item_t& item) { | 789 | braces_expression_error = pl::user(true_(), [](const item_t& item) { |
| 779 | throw ParserError("syntax error in brace expression", *item.begin, *item.end); | 790 | throw ParserError("syntax error in brace expression"sv, item.begin); |
| 780 | return false; | 791 | return false; |
| 781 | }); | 792 | }); |
| 782 | 793 | ||
| 783 | brackets_expression_error = pl::user(true_(), [](const item_t& item) { | 794 | brackets_expression_error = pl::user(true_(), [](const item_t& item) { |
| 784 | throw ParserError("syntax error in bracket expression", *item.begin, *item.end); | 795 | throw ParserError("syntax error in bracket expression"sv, item.begin); |
| 785 | return false; | 796 | return false; |
| 786 | }); | 797 | }); |
| 787 | 798 | ||
| @@ -846,7 +857,7 @@ YueParser::YueParser() { | |||
| 846 | ) >> and_(line_break); | 857 | ) >> and_(line_break); |
| 847 | 858 | ||
| 848 | indentation_error = pl::user(not_(pipe_operator | eof()), [](const item_t& item) { | 859 | indentation_error = pl::user(not_(pipe_operator | eof()), [](const item_t& item) { |
| 849 | throw ParserError("unexpected indent", *item.begin, *item.end); | 860 | throw ParserError("unexpected indent"sv, item.begin); |
| 850 | return false; | 861 | return false; |
| 851 | }); | 862 | }); |
| 852 | 863 | ||
| @@ -875,7 +886,7 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) { | |||
| 875 | res.codes = std::make_unique<input>(); | 886 | res.codes = std::make_unique<input>(); |
| 876 | } | 887 | } |
| 877 | } catch (const std::range_error&) { | 888 | } catch (const std::range_error&) { |
| 878 | res.error = "invalid text encoding"sv; | 889 | res.error = {"invalid text encoding"s, 1, 1}; |
| 879 | return res; | 890 | return res; |
| 880 | } | 891 | } |
| 881 | error_list errors; | 892 | error_list errors; |
| @@ -888,26 +899,22 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) { | |||
| 888 | res.exportMacro = state.exportMacro; | 899 | res.exportMacro = state.exportMacro; |
| 889 | } | 900 | } |
| 890 | } catch (const ParserError& err) { | 901 | } catch (const ParserError& err) { |
| 891 | res.error = res.errorMessage(err.what(), &err.loc); | 902 | res.error = {err.what(), err.line, err.col}; |
| 892 | return res; | 903 | return res; |
| 893 | } catch (const std::logic_error& err) { | 904 | } catch (const std::logic_error& err) { |
| 894 | res.error = err.what(); | 905 | res.error = {err.what(), 1, 1}; |
| 895 | return res; | 906 | return res; |
| 896 | } | 907 | } |
| 897 | if (!errors.empty()) { | 908 | if (!errors.empty()) { |
| 898 | std::ostringstream buf; | 909 | const error& err = errors.front(); |
| 899 | for (error_list::iterator it = errors.begin(); it != errors.end(); ++it) { | 910 | switch (err.m_type) { |
| 900 | const error& err = *it; | 911 | case ERROR_TYPE::ERROR_SYNTAX_ERROR: |
| 901 | switch (err.m_type) { | 912 | res.error = {"syntax error"s, err.m_begin.m_line, err.m_begin.m_col}; |
| 902 | case ERROR_TYPE::ERROR_SYNTAX_ERROR: | 913 | break; |
| 903 | buf << res.errorMessage("syntax error"sv, &err); | 914 | case ERROR_TYPE::ERROR_INVALID_EOF: |
| 904 | break; | 915 | res.error = {"invalid EOF"s, err.m_begin.m_line, err.m_begin.m_col}; |
| 905 | case ERROR_TYPE::ERROR_INVALID_EOF: | 916 | break; |
| 906 | buf << res.errorMessage("invalid EOF"sv, &err); | ||
| 907 | break; | ||
| 908 | } | ||
| 909 | } | 917 | } |
| 910 | res.error = buf.str(); | ||
| 911 | } | 918 | } |
| 912 | return res; | 919 | return res; |
| 913 | } | 920 | } |
| @@ -944,9 +951,9 @@ void trim(std::string& str) { | |||
| 944 | } | 951 | } |
| 945 | } // namespace Utils | 952 | } // namespace Utils |
| 946 | 953 | ||
| 947 | std::string ParseInfo::errorMessage(std::string_view msg, const input_range* loc) const { | 954 | std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol) const { |
| 948 | const int ASCII = 255; | 955 | const int ASCII = 255; |
| 949 | int length = loc->m_begin.m_line; | 956 | int length = errLine; |
| 950 | auto begin = codes->begin(); | 957 | auto begin = codes->begin(); |
| 951 | auto end = codes->end(); | 958 | auto end = codes->end(); |
| 952 | int count = 0; | 959 | int count = 0; |
| @@ -961,7 +968,7 @@ std::string ParseInfo::errorMessage(std::string_view msg, const input_range* loc | |||
| 961 | count++; | 968 | count++; |
| 962 | } | 969 | } |
| 963 | } | 970 | } |
| 964 | int oldCol = loc->m_begin.m_col; | 971 | int oldCol = errCol; |
| 965 | int col = std::max(0, oldCol - 1); | 972 | int col = std::max(0, oldCol - 1); |
| 966 | auto it = begin; | 973 | auto it = begin; |
| 967 | for (int i = 0; i < oldCol && it != end; ++i) { | 974 | for (int i = 0; i < oldCol && it != end; ++i) { |
| @@ -977,7 +984,7 @@ std::string ParseInfo::errorMessage(std::string_view msg, const input_range* loc | |||
| 977 | } | 984 | } |
| 978 | Utils::replace(line, "\t"sv, " "sv); | 985 | Utils::replace(line, "\t"sv, " "sv); |
| 979 | std::ostringstream buf; | 986 | std::ostringstream buf; |
| 980 | buf << loc->m_begin.m_line << ": "sv << msg << '\n' | 987 | buf << errLine << ": "sv << msg << '\n' |
| 981 | << line << '\n' | 988 | << line << '\n' |
| 982 | << std::string(col, ' ') << "^"sv; | 989 | << std::string(col, ' ') << "^"sv; |
| 983 | return buf.str(); | 990 | return buf.str(); |
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index cce6741..31134e1 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h | |||
| @@ -11,6 +11,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI | |||
| 11 | #include <algorithm> | 11 | #include <algorithm> |
| 12 | #include <list> | 12 | #include <list> |
| 13 | #include <memory> | 13 | #include <memory> |
| 14 | #include <optional> | ||
| 14 | #include <sstream> | 15 | #include <sstream> |
| 15 | #include <stack> | 16 | #include <stack> |
| 16 | #include <string> | 17 | #include <string> |
| @@ -26,25 +27,18 @@ using namespace std::string_literals; | |||
| 26 | using namespace parserlib; | 27 | using namespace parserlib; |
| 27 | 28 | ||
| 28 | struct ParseInfo { | 29 | struct ParseInfo { |
| 30 | struct Error { | ||
| 31 | std::string msg; | ||
| 32 | int line; | ||
| 33 | int col; | ||
| 34 | }; | ||
| 29 | ast_ptr<false, ast_node> node; | 35 | ast_ptr<false, ast_node> node; |
| 30 | std::string error; | 36 | std::optional<Error> error; |
| 31 | std::unique_ptr<input> codes; | 37 | std::unique_ptr<input> codes; |
| 32 | bool exportDefault = false; | 38 | bool exportDefault = false; |
| 33 | bool exportMacro = false; | 39 | bool exportMacro = false; |
| 34 | std::string moduleName; | 40 | std::string moduleName; |
| 35 | std::string errorMessage(std::string_view msg, const input_range* loc) const; | 41 | std::string errorMessage(std::string_view msg, int errLine, int errCol) const; |
| 36 | }; | ||
| 37 | |||
| 38 | class ParserError : public std::logic_error { | ||
| 39 | public: | ||
| 40 | explicit ParserError(const std::string& msg, const pos& begin, const pos& end) | ||
| 41 | : std::logic_error(msg) | ||
| 42 | , loc(begin, end) { } | ||
| 43 | |||
| 44 | explicit ParserError(const char* msg, const pos& begin, const pos& end) | ||
| 45 | : std::logic_error(msg) | ||
| 46 | , loc(begin, end) { } | ||
| 47 | input_range loc; | ||
| 48 | }; | 42 | }; |
| 49 | 43 | ||
| 50 | template <typename T> | 44 | template <typename T> |
| @@ -53,21 +47,21 @@ struct identity { | |||
| 53 | }; | 47 | }; |
| 54 | 48 | ||
| 55 | #ifdef NDEBUG | 49 | #ifdef NDEBUG |
| 56 | #define NONE_AST_RULE(type) \ | 50 | #define NONE_AST_RULE(type) \ |
| 57 | rule type; | 51 | rule type; |
| 58 | 52 | ||
| 59 | #define AST_RULE(type) \ | 53 | #define AST_RULE(type) \ |
| 60 | rule type; \ | 54 | rule type; \ |
| 61 | ast<type##_t> type##_impl = type; \ | 55 | ast<type##_t> type##_impl = type; \ |
| 62 | inline rule& getRule(identity<type##_t>) { return type; } | 56 | inline rule& getRule(identity<type##_t>) { return type; } |
| 63 | #else // NDEBUG | 57 | #else // NDEBUG |
| 64 | #define NONE_AST_RULE(type) \ | 58 | #define NONE_AST_RULE(type) \ |
| 65 | rule type{#type, rule::initTag{}}; | 59 | rule type{#type, rule::initTag{}}; |
| 66 | 60 | ||
| 67 | #define AST_RULE(type) \ | 61 | #define AST_RULE(type) \ |
| 68 | rule type{#type, rule::initTag{}}; \ | 62 | rule type{#type, rule::initTag{}}; \ |
| 69 | ast<type##_t> type##_impl = type; \ | 63 | ast<type##_t> type##_impl = type; \ |
| 70 | inline rule& getRule(identity<type##_t>) { return type; } | 64 | inline rule& getRule(identity<type##_t>) { return type; } |
| 71 | #endif // NDEBUG | 65 | #endif // NDEBUG |
| 72 | 66 | ||
| 73 | extern std::unordered_set<std::string> LuaKeywords; | 67 | extern std::unordered_set<std::string> LuaKeywords; |
diff --git a/src/yuescript/yuescript.cpp b/src/yuescript/yuescript.cpp index b5043e0..ef427ad 100644 --- a/src/yuescript/yuescript.cpp +++ b/src/yuescript/yuescript.cpp | |||
| @@ -62,43 +62,55 @@ static int init_stacktraceplus(lua_State* L) { | |||
| 62 | return 1; | 62 | return 1; |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | static yue::YueConfig get_config(lua_State* L) { | ||
| 66 | yue::YueConfig config; | ||
| 67 | lua_pushliteral(L, "lint_global"); | ||
| 68 | lua_gettable(L, -2); | ||
| 69 | if (lua_isboolean(L, -1) != 0) { | ||
| 70 | config.lintGlobalVariable = lua_toboolean(L, -1) != 0; | ||
| 71 | } | ||
| 72 | lua_pop(L, 1); | ||
| 73 | lua_pushliteral(L, "implicit_return_root"); | ||
| 74 | lua_gettable(L, -2); | ||
| 75 | if (lua_isboolean(L, -1) != 0) { | ||
| 76 | config.implicitReturnRoot = lua_toboolean(L, -1) != 0; | ||
| 77 | } | ||
| 78 | lua_pop(L, 1); | ||
| 79 | lua_pushliteral(L, "reserve_line_number"); | ||
| 80 | lua_gettable(L, -2); | ||
| 81 | if (lua_isboolean(L, -1) != 0) { | ||
| 82 | config.reserveLineNumber = lua_toboolean(L, -1) != 0; | ||
| 83 | } | ||
| 84 | lua_pop(L, 1); | ||
| 85 | lua_pushliteral(L, "reserve_comment"); | ||
| 86 | lua_gettable(L, -2); | ||
| 87 | if (lua_isboolean(L, -1) != 0) { | ||
| 88 | config.reserveComment = lua_toboolean(L, -1) != 0; | ||
| 89 | } | ||
| 90 | lua_pop(L, 1); | ||
| 91 | lua_pushliteral(L, "space_over_tab"); | ||
| 92 | lua_gettable(L, -2); | ||
| 93 | if (lua_isboolean(L, -1) != 0) { | ||
| 94 | config.useSpaceOverTab = lua_toboolean(L, -1) != 0; | ||
| 95 | } | ||
| 96 | lua_pop(L, 1); | ||
| 97 | lua_pushliteral(L, "target"); | ||
| 98 | lua_gettable(L, -2); | ||
| 99 | if (lua_isstring(L, -1) != 0) { | ||
| 100 | config.options["target"] = lua_tostring(L, -1); | ||
| 101 | } | ||
| 102 | lua_pop(L, 1); | ||
| 103 | return config; | ||
| 104 | } | ||
| 105 | |||
| 65 | static int yuetolua(lua_State* L) { | 106 | static int yuetolua(lua_State* L) { |
| 66 | size_t size = 0; | 107 | size_t len = 0; |
| 67 | const char* input = luaL_checklstring(L, 1, &size); | 108 | std::string codes(luaL_checklstring(L, 1, &len), len); |
| 68 | yue::YueConfig config; | 109 | yue::YueConfig config; |
| 69 | bool sameModule = false; | 110 | bool sameModule = false; |
| 70 | if (lua_gettop(L) == 2) { | 111 | if (lua_gettop(L) == 2) { |
| 71 | luaL_checktype(L, 2, LUA_TTABLE); | 112 | luaL_checktype(L, 2, LUA_TTABLE); |
| 72 | lua_pushliteral(L, "lint_global"); | 113 | config = get_config(L); |
| 73 | lua_gettable(L, -2); | ||
| 74 | if (lua_isboolean(L, -1) != 0) { | ||
| 75 | config.lintGlobalVariable = lua_toboolean(L, -1) != 0; | ||
| 76 | } | ||
| 77 | lua_pop(L, 1); | ||
| 78 | lua_pushliteral(L, "implicit_return_root"); | ||
| 79 | lua_gettable(L, -2); | ||
| 80 | if (lua_isboolean(L, -1) != 0) { | ||
| 81 | config.implicitReturnRoot = lua_toboolean(L, -1) != 0; | ||
| 82 | } | ||
| 83 | lua_pop(L, 1); | ||
| 84 | lua_pushliteral(L, "reserve_line_number"); | ||
| 85 | lua_gettable(L, -2); | ||
| 86 | if (lua_isboolean(L, -1) != 0) { | ||
| 87 | config.reserveLineNumber = lua_toboolean(L, -1) != 0; | ||
| 88 | } | ||
| 89 | lua_pop(L, 1); | ||
| 90 | lua_pushliteral(L, "reserve_comment"); | ||
| 91 | lua_gettable(L, -2); | ||
| 92 | if (lua_isboolean(L, -1) != 0) { | ||
| 93 | config.reserveComment = lua_toboolean(L, -1) != 0; | ||
| 94 | } | ||
| 95 | lua_pop(L, 1); | ||
| 96 | lua_pushliteral(L, "space_over_tab"); | ||
| 97 | lua_gettable(L, -2); | ||
| 98 | if (lua_isboolean(L, -1) != 0) { | ||
| 99 | config.useSpaceOverTab = lua_toboolean(L, -1) != 0; | ||
| 100 | } | ||
| 101 | lua_pop(L, 1); | ||
| 102 | lua_pushliteral(L, "same_module"); | 114 | lua_pushliteral(L, "same_module"); |
| 103 | lua_gettable(L, -2); | 115 | lua_gettable(L, -2); |
| 104 | if (lua_isboolean(L, -1) != 0) { | 116 | if (lua_isboolean(L, -1) != 0) { |
| @@ -117,24 +129,18 @@ static int yuetolua(lua_State* L) { | |||
| 117 | config.module = lua_tostring(L, -1); | 129 | config.module = lua_tostring(L, -1); |
| 118 | } | 130 | } |
| 119 | lua_pop(L, 1); | 131 | lua_pop(L, 1); |
| 120 | lua_pushliteral(L, "target"); | ||
| 121 | lua_gettable(L, -2); | ||
| 122 | if (lua_isstring(L, -1) != 0) { | ||
| 123 | config.options["target"] = lua_tostring(L, -1); | ||
| 124 | } | ||
| 125 | lua_pop(L, 1); | ||
| 126 | } | 132 | } |
| 127 | std::string s(input, size); | 133 | auto result = yue::YueCompiler(L, nullptr, sameModule).compile(codes, config); |
| 128 | auto result = yue::YueCompiler(L, nullptr, sameModule).compile(s, config); | 134 | if (result.error) { |
| 129 | if (result.codes.empty() && !result.error.empty()) { | ||
| 130 | lua_pushnil(L); | 135 | lua_pushnil(L); |
| 131 | } else { | 136 | } else { |
| 132 | lua_pushlstring(L, result.codes.c_str(), result.codes.size()); | 137 | lua_pushlstring(L, result.codes.c_str(), result.codes.size()); |
| 133 | } | 138 | } |
| 134 | if (result.error.empty()) { | 139 | if (result.error) { |
| 135 | lua_pushnil(L); | 140 | const auto& msg = result.error.value().displayMessage; |
| 141 | lua_pushlstring(L, msg.c_str(), msg.size()); | ||
| 136 | } else { | 142 | } else { |
| 137 | lua_pushlstring(L, result.error.c_str(), result.error.size()); | 143 | lua_pushnil(L); |
| 138 | } | 144 | } |
| 139 | if (result.globals) { | 145 | if (result.globals) { |
| 140 | lua_createtable(L, static_cast<int>(result.globals->size()), 0); | 146 | lua_createtable(L, static_cast<int>(result.globals->size()), 0); |
| @@ -156,6 +162,57 @@ static int yuetolua(lua_State* L) { | |||
| 156 | return 3; | 162 | return 3; |
| 157 | } | 163 | } |
| 158 | 164 | ||
| 165 | static int yuecheck(lua_State* L) { | ||
| 166 | size_t len = 0; | ||
| 167 | std::string codes{luaL_checklstring(L, 1, &len), len}; | ||
| 168 | yue::YueConfig config; | ||
| 169 | config.lintGlobalVariable = true; | ||
| 170 | if (lua_gettop(L) == 2) { | ||
| 171 | luaL_checktype(L, 2, LUA_TTABLE); | ||
| 172 | config = get_config(L); | ||
| 173 | } | ||
| 174 | auto result = yue::YueCompiler(L).compile(codes, config); | ||
| 175 | lua_createtable(L, 0, 0); | ||
| 176 | int i = 0; | ||
| 177 | if (result.error) { | ||
| 178 | const auto& error = result.error.value(); | ||
| 179 | lua_createtable(L, 4, 0); | ||
| 180 | lua_pushliteral(L, "error"); | ||
| 181 | lua_rawseti(L, -2, 1); | ||
| 182 | lua_pushlstring(L, error.msg.c_str(), error.msg.length()); | ||
| 183 | lua_rawseti(L, -2, 2); | ||
| 184 | lua_pushinteger(L, error.line); | ||
| 185 | lua_rawseti(L, -2, 3); | ||
| 186 | lua_pushinteger(L, error.col); | ||
| 187 | lua_rawseti(L, -2, 4); | ||
| 188 | lua_rawseti(L, -2, ++i); | ||
| 189 | } | ||
| 190 | if (result.globals) { | ||
| 191 | for (const auto& global : *result.globals) { | ||
| 192 | lua_createtable(L, 4, 0); | ||
| 193 | lua_pushliteral(L, "global"); | ||
| 194 | lua_rawseti(L, -2, 1); | ||
| 195 | lua_pushlstring(L, global.name.c_str(), global.name.length()); | ||
| 196 | lua_rawseti(L, -2, 2); | ||
| 197 | lua_pushinteger(L, global.line); | ||
| 198 | lua_rawseti(L, -2, 3); | ||
| 199 | lua_pushinteger(L, global.col); | ||
| 200 | lua_rawseti(L, -2, 4); | ||
| 201 | lua_rawseti(L, -2, ++i); | ||
| 202 | } | ||
| 203 | } | ||
| 204 | if (result.error) { | ||
| 205 | lua_pushboolean(L, 0); | ||
| 206 | lua_insert(L, -2); | ||
| 207 | return 2; | ||
| 208 | } else { | ||
| 209 | lua_pushboolean(L, 1); | ||
| 210 | lua_insert(L, -2); | ||
| 211 | lua_pushlstring(L, result.codes.c_str(), result.codes.length()); | ||
| 212 | return 3; | ||
| 213 | } | ||
| 214 | } | ||
| 215 | |||
| 159 | struct yue_stack { | 216 | struct yue_stack { |
| 160 | int continuation; | 217 | int continuation; |
| 161 | yue::ast_node* node; | 218 | yue::ast_node* node; |
| @@ -174,7 +231,7 @@ static int yuetoast(lua_State* L) { | |||
| 174 | } | 231 | } |
| 175 | yue::YueParser parser; | 232 | yue::YueParser parser; |
| 176 | auto info = parser.parse<yue::File_t>({input, size}); | 233 | auto info = parser.parse<yue::File_t>({input, size}); |
| 177 | if (info.node) { | 234 | if (!info.error) { |
| 178 | lua_createtable(L, 0, 0); | 235 | lua_createtable(L, 0, 0); |
| 179 | int tableIndex = lua_gettop(L); | 236 | int tableIndex = lua_gettop(L); |
| 180 | lua_createtable(L, 0, 0); | 237 | lua_createtable(L, 0, 0); |
| @@ -300,7 +357,8 @@ static int yuetoast(lua_State* L) { | |||
| 300 | return 1; | 357 | return 1; |
| 301 | } else { | 358 | } else { |
| 302 | lua_pushnil(L); | 359 | lua_pushnil(L); |
| 303 | lua_pushlstring(L, info.error.c_str(), info.error.length()); | 360 | const auto& msg = info.error.value().msg; |
| 361 | lua_pushlstring(L, msg.c_str(), msg.length()); | ||
| 304 | return 2; | 362 | return 2; |
| 305 | } | 363 | } |
| 306 | } | 364 | } |
| @@ -308,6 +366,7 @@ static int yuetoast(lua_State* L) { | |||
| 308 | static const luaL_Reg yuelib[] = { | 366 | static const luaL_Reg yuelib[] = { |
| 309 | {"to_lua", yuetolua}, | 367 | {"to_lua", yuetolua}, |
| 310 | {"to_ast", yuetoast}, | 368 | {"to_ast", yuetoast}, |
| 369 | {"check", yuecheck}, | ||
| 311 | {"version", nullptr}, | 370 | {"version", nullptr}, |
| 312 | {"options", nullptr}, | 371 | {"options", nullptr}, |
| 313 | {"load_stacktraceplus", nullptr}, | 372 | {"load_stacktraceplus", nullptr}, |
diff --git a/src/yuescript/yuescript.h b/src/yuescript/yuescript.h index 2d2d660..51622f8 100644 --- a/src/yuescript/yuescript.h +++ b/src/yuescript/yuescript.h | |||
| @@ -56,7 +56,12 @@ end | |||
| 56 | local function find_modulepath(name) | 56 | local function find_modulepath(name) |
| 57 | local suffix = "." .. yue.options.extension | 57 | local suffix = "." .. yue.options.extension |
| 58 | local dirsep = yue.options.dirsep | 58 | local dirsep = yue.options.dirsep |
| 59 | local name_path = name:match("[\\/]") and name or name:gsub("%.", dirsep) | 59 | local name_path |
| 60 | if name:match("[\\/]") then | ||
| 61 | name_path = name:gsub("%" .. suffix .. "$", "") | ||
| 62 | else | ||
| 63 | name_path = name:gsub("%.", dirsep) | ||
| 64 | end | ||
| 60 | local file_exist, file_path | 65 | local file_exist, file_path |
| 61 | local tried = {} | 66 | local tried = {} |
| 62 | local paths = {package.path, yue.options.path} | 67 | local paths = {package.path, yue.options.path} |
