diff options
author | Li Jin <dragon-fly@qq.com> | 2022-12-28 15:55:15 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2022-12-28 15:55:15 +0800 |
commit | dba662758192b41648e6c1201083d83926f07783 (patch) | |
tree | 4eca06097fce6ac52bbf5276a6ac2da4affb90d0 /src | |
parent | 5e453de810f8a5e54351609857d742481f057498 (diff) | |
download | yuescript-dba662758192b41648e6c1201083d83926f07783.tar.gz yuescript-dba662758192b41648e6c1201083d83926f07783.tar.bz2 yuescript-dba662758192b41648e6c1201083d83926f07783.zip |
add metamethods checking.
Diffstat (limited to 'src')
-rw-r--r-- | src/yuescript/yue_compiler.cpp | 112 |
1 files changed, 102 insertions, 10 deletions
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 0d674f8..42310b2 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
@@ -60,7 +60,18 @@ namespace yue { | |||
60 | 60 | ||
61 | typedef std::list<std::string> str_list; | 61 | typedef std::list<std::string> str_list; |
62 | 62 | ||
63 | const std::string_view version = "0.15.18"sv; | 63 | static std::unordered_set<std::string> Metamethods = { |
64 | "add"s, "sub"s, "mul"s, "div"s, "mod"s, | ||
65 | "pow"s, "unm"s, "concat"s, "len"s, "eq"s, | ||
66 | "lt"s, "le"s, "index"s, "newindex"s, "call"s, | ||
67 | "gc"s, "mode"s, "tostring"s, "metatable"s, // Lua 5.1 | ||
68 | "pairs"s, "ipairs"s, // Lua 5.2 | ||
69 | "name"s, "idiv"s, "band"s, "bor"s, "bxor"s, | ||
70 | "bnot"s, "shl"s, "shr"s, // Lua 5.3 ipairs deprecated | ||
71 | "close"s // Lua 5.4 | ||
72 | }; | ||
73 | |||
74 | const std::string_view version = "0.15.19"sv; | ||
64 | const std::string_view extension = "yue"sv; | 75 | const std::string_view extension = "yue"sv; |
65 | 76 | ||
66 | class YueCompilerImpl { | 77 | class YueCompilerImpl { |
@@ -1089,6 +1100,46 @@ private: | |||
1089 | return str; | 1100 | return str; |
1090 | } | 1101 | } |
1091 | 1102 | ||
1103 | void checkMetamethod(const std::string& name, ast_node* x) { | ||
1104 | if (Metamethods.find(name) == Metamethods.end()) { | ||
1105 | throw std::logic_error(_info.errorMessage("invalid metamethod name"sv, x)); | ||
1106 | } | ||
1107 | int target = getLuaTarget(x); | ||
1108 | switch (target) { | ||
1109 | case 501: goto metamethod51; | ||
1110 | case 502: goto metamethod52; | ||
1111 | case 503: { | ||
1112 | if (name == "ipairs"sv) { | ||
1113 | throw std::logic_error(_info.errorMessage("metamethod is deprecated since Lua 5.3"sv, x)); | ||
1114 | } | ||
1115 | goto metamethod53; | ||
1116 | } | ||
1117 | case 504: { | ||
1118 | if (name == "ipairs"sv) { | ||
1119 | throw std::logic_error(_info.errorMessage("metamethod is not supported since Lua 5.4"sv, x)); | ||
1120 | } | ||
1121 | goto metamethod54; | ||
1122 | } | ||
1123 | } | ||
1124 | metamethod51: | ||
1125 | if (name == "pairs"sv || name == "ipairs"sv) { | ||
1126 | throw std::logic_error(_info.errorMessage("metamethod is not supported until Lua 5.2"sv, x)); | ||
1127 | } | ||
1128 | metamethod52: | ||
1129 | if (name == "name"sv || name == "idiv"sv || | ||
1130 | name == "band"sv || name == "bor"sv || | ||
1131 | name == "bxor"sv || name == "bnot"sv || | ||
1132 | name == "shl"sv || name == "shr"sv) { | ||
1133 | throw std::logic_error(_info.errorMessage("metamethod is not supported until Lua 5.3"sv, x)); | ||
1134 | } | ||
1135 | metamethod53: | ||
1136 | if (name == "close"sv) { | ||
1137 | throw std::logic_error(_info.errorMessage("metamethod is not supported until Lua 5.4"sv, x)); | ||
1138 | } | ||
1139 | metamethod54: | ||
1140 | return; | ||
1141 | } | ||
1142 | |||
1092 | void transformStatement(Statement_t* statement, str_list& out) { | 1143 | void transformStatement(Statement_t* statement, str_list& out) { |
1093 | auto x = statement; | 1144 | auto x = statement; |
1094 | if (statement->appendix) { | 1145 | if (statement->appendix) { |
@@ -1825,11 +1876,32 @@ private: | |||
1825 | if (info.destructures.empty()) { | 1876 | if (info.destructures.empty()) { |
1826 | transformAssignmentCommon(assignment, out); | 1877 | transformAssignmentCommon(assignment, out); |
1827 | } else { | 1878 | } else { |
1879 | auto x = assignment; | ||
1828 | str_list temp; | 1880 | str_list temp; |
1881 | if (info.extraScope) { | ||
1882 | str_list defs; | ||
1883 | for (auto& destruct : info.destructures) { | ||
1884 | for (auto& item : destruct.items) { | ||
1885 | if (!item.targetVar.empty()) { | ||
1886 | if (!isDefined(item.targetVar)) { | ||
1887 | defs.push_back(item.targetVar); | ||
1888 | } | ||
1889 | } | ||
1890 | } | ||
1891 | } | ||
1892 | if (!defs.empty()) { | ||
1893 | for (const auto& def : defs) { | ||
1894 | checkConst(def, x); | ||
1895 | addToScope(def); | ||
1896 | } | ||
1897 | temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); | ||
1898 | } | ||
1899 | temp.push_back(indent() + "do"s + nll(x)); | ||
1900 | pushScope(); | ||
1901 | } | ||
1829 | if (info.assignment) { | 1902 | if (info.assignment) { |
1830 | transformAssignmentCommon(info.assignment, temp); | 1903 | transformAssignmentCommon(info.assignment, temp); |
1831 | } | 1904 | } |
1832 | auto x = assignment; | ||
1833 | for (auto& destruct : info.destructures) { | 1905 | for (auto& destruct : info.destructures) { |
1834 | std::list<std::pair<ast_ptr<true, Exp_t>, ast_ptr<true, Exp_t>>> leftPairs; | 1906 | std::list<std::pair<ast_ptr<true, Exp_t>, ast_ptr<true, Exp_t>>> leftPairs; |
1835 | bool extraScope = false; | 1907 | bool extraScope = false; |
@@ -1861,7 +1933,7 @@ private: | |||
1861 | } | 1933 | } |
1862 | } | 1934 | } |
1863 | if (!isNil) { | 1935 | if (!isNil) { |
1864 | auto stmt = toAst<Statement_t>(pair.targetVar + "=nil if "s + pair.targetVar + "==nil", pair.defVal); | 1936 | auto stmt = toAst<Statement_t>(pair.targetVar + "=nil if "s + pair.targetVar + "==nil"s, pair.defVal); |
1865 | auto defAssign = stmt->content.as<ExpListAssign_t>(); | 1937 | auto defAssign = stmt->content.as<ExpListAssign_t>(); |
1866 | auto assign = defAssign->action.as<Assign_t>(); | 1938 | auto assign = defAssign->action.as<Assign_t>(); |
1867 | assign->values.clear(); | 1939 | assign->values.clear(); |
@@ -2035,6 +2107,10 @@ private: | |||
2035 | temp.push_back(clearBuf()); | 2107 | temp.push_back(clearBuf()); |
2036 | } | 2108 | } |
2037 | } | 2109 | } |
2110 | if (info.extraScope) { | ||
2111 | popScope(); | ||
2112 | temp.push_back(indent() + "end"s + nlr(x)); | ||
2113 | } | ||
2038 | out.push_back(join(temp)); | 2114 | out.push_back(join(temp)); |
2039 | } | 2115 | } |
2040 | } | 2116 | } |
@@ -2247,6 +2323,7 @@ private: | |||
2247 | } | 2323 | } |
2248 | auto mp = static_cast<meta_variable_pair_t*>(pair); | 2324 | auto mp = static_cast<meta_variable_pair_t*>(pair); |
2249 | auto name = _parser.toString(mp->name); | 2325 | auto name = _parser.toString(mp->name); |
2326 | checkMetamethod(name, mp->name); | ||
2250 | _buf << "__"sv << name << ':' << name; | 2327 | _buf << "__"sv << name << ':' << name; |
2251 | auto newPairDef = toAst<normal_pair_def_t>(clearBuf(), pair); | 2328 | auto newPairDef = toAst<normal_pair_def_t>(clearBuf(), pair); |
2252 | newPairDef->defVal.set(defVal); | 2329 | newPairDef->defVal.set(defVal); |
@@ -2266,6 +2343,7 @@ private: | |||
2266 | switch (mp->key->getId()) { | 2343 | switch (mp->key->getId()) { |
2267 | case id<Name_t>(): { | 2344 | case id<Name_t>(): { |
2268 | auto key = _parser.toString(mp->key); | 2345 | auto key = _parser.toString(mp->key); |
2346 | checkMetamethod(key, mp->key); | ||
2269 | _buf << "__"sv << key; | 2347 | _buf << "__"sv << key; |
2270 | auto newKey = toAst<KeyName_t>(clearBuf(), mp->key); | 2348 | auto newKey = toAst<KeyName_t>(clearBuf(), mp->key); |
2271 | newPair->key.set(newKey); | 2349 | newPair->key.set(newKey); |
@@ -2309,10 +2387,12 @@ private: | |||
2309 | struct DestructureInfo { | 2387 | struct DestructureInfo { |
2310 | std::list<Destructure> destructures; | 2388 | std::list<Destructure> destructures; |
2311 | ast_ptr<false, ExpListAssign_t> assignment; | 2389 | ast_ptr<false, ExpListAssign_t> assignment; |
2390 | bool extraScope = false; | ||
2312 | }; | 2391 | }; |
2313 | 2392 | ||
2314 | DestructureInfo extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly, bool optional) { | 2393 | DestructureInfo extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly, bool optional) { |
2315 | auto x = assignment; | 2394 | auto x = assignment; |
2395 | bool extraScope = false; | ||
2316 | std::list<Destructure> destructs; | 2396 | std::list<Destructure> destructs; |
2317 | if (!assignment->action.is<Assign_t>()) return {destructs, nullptr}; | 2397 | if (!assignment->action.is<Assign_t>()) return {destructs, nullptr}; |
2318 | auto exprs = assignment->expList->exprs.objects(); | 2398 | auto exprs = assignment->expList->exprs.objects(); |
@@ -2367,6 +2447,7 @@ private: | |||
2367 | auto mvp = static_cast<meta_variable_pair_def_t*>(item); | 2447 | auto mvp = static_cast<meta_variable_pair_def_t*>(item); |
2368 | auto mp = mvp->pair.get(); | 2448 | auto mp = mvp->pair.get(); |
2369 | auto name = _parser.toString(mp->name); | 2449 | auto name = _parser.toString(mp->name); |
2450 | checkMetamethod(name, mp->name); | ||
2370 | _buf << "__"sv << name << ':' << name; | 2451 | _buf << "__"sv << name << ':' << name; |
2371 | auto newPairDef = toAst<normal_pair_def_t>(clearBuf(), item); | 2452 | auto newPairDef = toAst<normal_pair_def_t>(clearBuf(), item); |
2372 | newPairDef->defVal.set(mvp->defVal); | 2453 | newPairDef->defVal.set(mvp->defVal); |
@@ -2381,6 +2462,7 @@ private: | |||
2381 | switch (mp->key->getId()) { | 2462 | switch (mp->key->getId()) { |
2382 | case id<Name_t>(): { | 2463 | case id<Name_t>(): { |
2383 | auto key = _parser.toString(mp->key); | 2464 | auto key = _parser.toString(mp->key); |
2465 | checkMetamethod(key, mp->key); | ||
2384 | _buf << "__"sv << key; | 2466 | _buf << "__"sv << key; |
2385 | auto newKey = toAst<KeyName_t>(clearBuf(), mp->key); | 2467 | auto newKey = toAst<KeyName_t>(clearBuf(), mp->key); |
2386 | newPair->key.set(newKey); | 2468 | newPair->key.set(newKey); |
@@ -2406,6 +2488,7 @@ private: | |||
2406 | case id<meta_variable_pair_t>(): { | 2488 | case id<meta_variable_pair_t>(): { |
2407 | auto mp = static_cast<meta_variable_pair_t*>(item); | 2489 | auto mp = static_cast<meta_variable_pair_t*>(item); |
2408 | auto name = _parser.toString(mp->name); | 2490 | auto name = _parser.toString(mp->name); |
2491 | checkMetamethod(name, mp->name); | ||
2409 | _buf << "__"sv << name << ':' << name; | 2492 | _buf << "__"sv << name << ':' << name; |
2410 | auto newPairDef = toAst<normal_pair_def_t>(clearBuf(), item); | 2493 | auto newPairDef = toAst<normal_pair_def_t>(clearBuf(), item); |
2411 | subMetaDestruct->values.push_back(newPairDef); | 2494 | subMetaDestruct->values.push_back(newPairDef); |
@@ -2418,6 +2501,7 @@ private: | |||
2418 | switch (mp->key->getId()) { | 2501 | switch (mp->key->getId()) { |
2419 | case id<Name_t>(): { | 2502 | case id<Name_t>(): { |
2420 | auto key = _parser.toString(mp->key); | 2503 | auto key = _parser.toString(mp->key); |
2504 | checkMetamethod(key, mp->key); | ||
2421 | _buf << "__"sv << key; | 2505 | _buf << "__"sv << key; |
2422 | auto newKey = toAst<KeyName_t>(clearBuf(), mp->key); | 2506 | auto newKey = toAst<KeyName_t>(clearBuf(), mp->key); |
2423 | newPair->key.set(newKey); | 2507 | newPair->key.set(newKey); |
@@ -2462,12 +2546,16 @@ private: | |||
2462 | } | 2546 | } |
2463 | valueItems.push_back(*j); | 2547 | valueItems.push_back(*j); |
2464 | if (!varDefOnly && !subDestruct->values.empty() && !subMetaDestruct->values.empty()) { | 2548 | if (!varDefOnly && !subDestruct->values.empty() && !subMetaDestruct->values.empty()) { |
2465 | auto objVar = getUnusedName("_obj_"sv); | 2549 | auto var = singleVariableFrom(*j, false); |
2466 | addToScope(objVar); | 2550 | if (var.empty() || !isLocal(var)) { |
2467 | valueItems.pop_back(); | 2551 | auto objVar = getUnusedName("_obj_"sv); |
2468 | valueItems.push_back(toAst<Exp_t>(objVar, *j)); | 2552 | addToScope(objVar); |
2469 | exprs.push_back(valueItems.back()); | 2553 | valueItems.pop_back(); |
2470 | values.push_back(*j); | 2554 | valueItems.push_back(toAst<Exp_t>(objVar, *j)); |
2555 | exprs.push_back(valueItems.back()); | ||
2556 | values.push_back(*j); | ||
2557 | extraScope = true; | ||
2558 | } | ||
2471 | } | 2559 | } |
2472 | TableLit_t* tabs[] = {subDestruct.get(), subMetaDestruct.get()}; | 2560 | TableLit_t* tabs[] = {subDestruct.get(), subMetaDestruct.get()}; |
2473 | for (auto tab : tabs) { | 2561 | for (auto tab : tabs) { |
@@ -2573,7 +2661,7 @@ private: | |||
2573 | } | 2661 | } |
2574 | } | 2662 | } |
2575 | popScope(); | 2663 | popScope(); |
2576 | return {std::move(destructs), newAssignment}; | 2664 | return {std::move(destructs), newAssignment, extraScope}; |
2577 | } | 2665 | } |
2578 | 2666 | ||
2579 | void transformAssignmentCommon(ExpListAssign_t* assignment, str_list& out) { | 2667 | void transformAssignmentCommon(ExpListAssign_t* assignment, str_list& out) { |
@@ -5513,6 +5601,7 @@ private: | |||
5513 | throw std::logic_error(_info.errorMessage("too many metatable declarations"sv, mp->name)); | 5601 | throw std::logic_error(_info.errorMessage("too many metatable declarations"sv, mp->name)); |
5514 | } | 5602 | } |
5515 | auto name = _parser.toString(mp->name); | 5603 | auto name = _parser.toString(mp->name); |
5604 | checkMetamethod(name, mp->name); | ||
5516 | _buf << "__"sv << name << ':' << name; | 5605 | _buf << "__"sv << name << ':' << name; |
5517 | auto newPair = toAst<normal_pair_t>(clearBuf(), item); | 5606 | auto newPair = toAst<normal_pair_t>(clearBuf(), item); |
5518 | metatable->pairs.push_back(newPair); | 5607 | metatable->pairs.push_back(newPair); |
@@ -5529,6 +5618,7 @@ private: | |||
5529 | switch (mp->key->getId()) { | 5618 | switch (mp->key->getId()) { |
5530 | case id<Name_t>(): { | 5619 | case id<Name_t>(): { |
5531 | auto key = _parser.toString(mp->key); | 5620 | auto key = _parser.toString(mp->key); |
5621 | checkMetamethod(key, mp->key); | ||
5532 | _buf << "__"sv << key; | 5622 | _buf << "__"sv << key; |
5533 | auto newKey = toAst<KeyName_t>(clearBuf(), mp->key); | 5623 | auto newKey = toAst<KeyName_t>(clearBuf(), mp->key); |
5534 | newPair->key.set(newKey); | 5624 | newPair->key.set(newKey); |
@@ -6739,6 +6829,7 @@ private: | |||
6739 | case id<meta_variable_pair_t>(): { | 6829 | case id<meta_variable_pair_t>(): { |
6740 | auto mtPair = static_cast<meta_variable_pair_t*>(keyValue); | 6830 | auto mtPair = static_cast<meta_variable_pair_t*>(keyValue); |
6741 | auto nameStr = _parser.toString(mtPair->name); | 6831 | auto nameStr = _parser.toString(mtPair->name); |
6832 | checkMetamethod(nameStr, mtPair->name); | ||
6742 | ref.set(toAst<normal_pair_t>("__"s + nameStr + ':' + nameStr, keyValue)); | 6833 | ref.set(toAst<normal_pair_t>("__"s + nameStr + ':' + nameStr, keyValue)); |
6743 | keyValue = ref.get(); | 6834 | keyValue = ref.get(); |
6744 | break; | 6835 | break; |
@@ -6748,6 +6839,7 @@ private: | |||
6748 | auto normal_pair = keyValue->new_ptr<normal_pair_t>(); | 6839 | auto normal_pair = keyValue->new_ptr<normal_pair_t>(); |
6749 | if (auto name = mtPair->key.as<Name_t>()) { | 6840 | if (auto name = mtPair->key.as<Name_t>()) { |
6750 | auto nameStr = _parser.toString(name); | 6841 | auto nameStr = _parser.toString(name); |
6842 | checkMetamethod(nameStr, name); | ||
6751 | normal_pair->key.set(toAst<KeyName_t>("__"s + nameStr, keyValue)); | 6843 | normal_pair->key.set(toAst<KeyName_t>("__"s + nameStr, keyValue)); |
6752 | } else if (auto str = mtPair->key.as<String_t>()) { | 6844 | } else if (auto str = mtPair->key.as<String_t>()) { |
6753 | normal_pair->key.set(newExp(str, str)); | 6845 | normal_pair->key.set(newExp(str, str)); |