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/yuescript/yue_compiler.cpp | |
| parent | 5e453de810f8a5e54351609857d742481f057498 (diff) | |
| download | yuescript-dba662758192b41648e6c1201083d83926f07783.tar.gz yuescript-dba662758192b41648e6c1201083d83926f07783.tar.bz2 yuescript-dba662758192b41648e6c1201083d83926f07783.zip | |
add metamethods checking.
Diffstat (limited to '')
| -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)); |
