aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2023-03-23 09:50:56 +0800
committerLi Jin <dragon-fly@qq.com>2023-03-23 09:51:15 +0800
commitf52f54f953feb6bb36a279c42882d7a744695271 (patch)
treee71f1df9ff282adf01938b652ce35894d463ce9d
parenta359ad7a16966c8955ec29e287b78d6a71dd0030 (diff)
downloadyuescript-f52f54f953feb6bb36a279c42882d7a744695271.tar.gz
yuescript-f52f54f953feb6bb36a279c42882d7a744695271.tar.bz2
yuescript-f52f54f953feb6bb36a279c42882d7a744695271.zip
add yue.check function.
-rw-r--r--src/yuescript/stacktraceplus.h2
-rw-r--r--src/yuescript/yue_compiler.cpp405
-rw-r--r--src/yuescript/yue_compiler.h22
-rw-r--r--src/yuescript/yue_parser.cpp63
-rw-r--r--src/yuescript/yue_parser.h46
-rw-r--r--src/yuescript/yuescript.cpp151
-rw-r--r--src/yuescript/yuescript.h7
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
63typedef std::list<std::string> str_list; 62typedef 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
76const std::string_view version = "0.15.28"sv; 75const std::string_view version = "0.15.29"sv;
77const std::string_view extension = "yue"sv; 76const std::string_view extension = "yue"sv;
78 77
78class CompileError : public std::logic_error {
79public:
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
89CompileInfo::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
103CompileInfo::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
111void 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
79class YueCompilerImpl { 120class YueCompilerImpl {
80public: 121public:
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
49struct CompileInfo { 50struct 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
58class YueCompilerImpl; 76class 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
33class ParserError : public std::logic_error {
34public:
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
34YueParser::YueParser() { 45YueParser::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
947std::string ParseInfo::errorMessage(std::string_view msg, const input_range* loc) const { 954std::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;
26using namespace parserlib; 27using namespace parserlib;
27 28
28struct ParseInfo { 29struct 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
38class ParserError : public std::logic_error {
39public:
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
50template <typename T> 44template <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
73extern std::unordered_set<std::string> LuaKeywords; 67extern 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
65static 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
65static int yuetolua(lua_State* L) { 106static 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
165static 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
159struct yue_stack { 216struct 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) {
308static const luaL_Reg yuelib[] = { 366static 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
56local function find_modulepath(name) 56local 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}