aboutsummaryrefslogtreecommitdiff
path: root/src/yuescript/yue_compiler.cpp
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2023-05-17 09:19:20 +0800
committerLi Jin <dragon-fly@qq.com>2023-05-17 09:19:20 +0800
commit78d5e6f44c06ac24aee667b5f9a9e642dcc6208d (patch)
tree78913f601c44a1d85e275a30e4a1272fee00c4cb /src/yuescript/yue_compiler.cpp
parenta8c4737494818e6591cac2191bf3a49cbe990173 (diff)
downloadyuescript-78d5e6f44c06ac24aee667b5f9a9e642dcc6208d.tar.gz
yuescript-78d5e6f44c06ac24aee667b5f9a9e642dcc6208d.tar.bz2
yuescript-78d5e6f44c06ac24aee667b5f9a9e642dcc6208d.zip
fix issue #133.
Diffstat (limited to '')
-rw-r--r--src/yuescript/yue_compiler.cpp170
1 files changed, 138 insertions, 32 deletions
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index 5c8ff5e..b131eff 100644
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -72,7 +72,7 @@ static std::unordered_set<std::string> Metamethods = {
72 "close"s // Lua 5.4 72 "close"s // Lua 5.4
73}; 73};
74 74
75const std::string_view version = "0.16.3"sv; 75const std::string_view version = "0.16.4"sv;
76const std::string_view extension = "yue"sv; 76const std::string_view extension = "yue"sv;
77 77
78class CompileError : public std::logic_error { 78class CompileError : public std::logic_error {
@@ -395,6 +395,8 @@ private:
395 int level; 395 int level;
396 }; 396 };
397 std::list<GotoNode> gotos; 397 std::list<GotoNode> gotos;
398 std::unordered_set<std::string> _exportedKeys;
399 std::unordered_set<std::string> _exportedMetaKeys;
398 400
399 enum class LocalMode { 401 enum class LocalMode {
400 None = 0, 402 None = 0,
@@ -778,7 +780,15 @@ private:
778 Value_t* singleValueFrom(ast_node* item) const { 780 Value_t* singleValueFrom(ast_node* item) const {
779 if (auto unary = singleUnaryExpFrom(item)) { 781 if (auto unary = singleUnaryExpFrom(item)) {
780 if (unary->ops.empty()) { 782 if (unary->ops.empty()) {
781 return static_cast<Value_t*>(unary->expos.back()); 783 Value_t* value = static_cast<Value_t*>(unary->expos.back());
784 if (auto chain = ast_cast<ChainValue_t>(value->item); chain && chain->items.size() == 1) {
785 if (auto exp = chain->getByPath<Callable_t, Parens_t, Exp_t>()) {
786 if (auto insideValue = singleValueFrom(exp)) {
787 return insideValue;
788 }
789 }
790 }
791 return value;
782 } 792 }
783 } 793 }
784 return nullptr; 794 return nullptr;
@@ -3626,7 +3636,7 @@ private:
3626 ClassDecl_t* classDecl = nullptr; 3636 ClassDecl_t* classDecl = nullptr;
3627 ast_ptr<false, ExpListAssign_t> assignment; 3637 ast_ptr<false, ExpListAssign_t> assignment;
3628 if (auto exportNode = stmt->content.as<Export_t>()) { 3638 if (auto exportNode = stmt->content.as<Export_t>()) {
3629 if (exportNode->assign) { 3639 if (exportNode->assign && exportNode->target.is<ExpList_t>()) {
3630 assignment = stmt->new_ptr<ExpListAssign_t>(); 3640 assignment = stmt->new_ptr<ExpListAssign_t>();
3631 assignment->expList.set(exportNode->target); 3641 assignment->expList.set(exportNode->target);
3632 assignment->action.set(exportNode->assign); 3642 assignment->action.set(exportNode->assign);
@@ -3694,7 +3704,7 @@ private:
3694 } 3704 }
3695 } 3705 }
3696 if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) { 3706 if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) {
3697 block->statements.push_front(toAst<Statement_t>(_info.moduleName + (_info.exportDefault ? "=nil"s : "={}"s), block)); 3707 block->statements.push_front(toAst<Statement_t>(_info.moduleName + (_info.exportDefault ? "=nil"s : (_info.exportMetatable ? "=<>:{}"s : "={}"s)), block));
3698 } 3708 }
3699 switch (usage) { 3709 switch (usage) {
3700 case ExpUsage::Closure: 3710 case ExpUsage::Closure:
@@ -7363,43 +7373,139 @@ private:
7363 } 7373 }
7364 } 7374 }
7365 7375
7376 std::optional<std::string> getExportKey(ast_node* node) {
7377 switch (node->getId()) {
7378 case id<Name_t>(): {
7379 return _parser.toString(node);
7380 }
7381 case id<String_t>(): {
7382 auto strNode = static_cast<String_t*>(node);
7383 switch (strNode->str->getId()) {
7384 case id<DoubleString_t>(): {
7385 auto str = static_cast<DoubleString_t*>(strNode->str.get());
7386 if (str->segments.size() == 1) {
7387 auto content = static_cast<DoubleStringContent_t*>(str->segments.front());
7388 if (auto inner = content->content.as<DoubleStringInner_t>()) {
7389 return _parser.toString(inner);
7390 }
7391 }
7392 return std::nullopt;
7393 }
7394 case id<SingleString_t>(): {
7395 auto str = _parser.toString(strNode->str);
7396 Utils::replace(str, "\r\n"sv, "\n");
7397 return str.substr(1, str.length() - 2);
7398 }
7399 case id<LuaString_t>(): {
7400 auto str = static_cast<LuaString_t*>(strNode->str.get());
7401 return _parser.toString(str->content);
7402 }
7403 default: {
7404 YUEE("AST node mismatch", strNode->str);
7405 return std::nullopt;
7406 }
7407 }
7408 }
7409 case id<Metamethod_t>(): {
7410 auto metamethod = static_cast<Metamethod_t*>(node);
7411 if (auto key = getExportKey(metamethod->item)) {
7412 if (metamethod->item.is<Name_t>()) {
7413 return "__"s + key.value();
7414 } else {
7415 return key;
7416 }
7417 }
7418 return std::nullopt;
7419 }
7420 case id<DotChainItem_t>(): {
7421 auto dotChain = static_cast<DotChainItem_t*>(node);
7422 return getExportKey(dotChain->name);
7423 }
7424 case id<Exp_t>(): {
7425 if (auto value = singleValueFrom(node)) {
7426 if (auto str = value->item.as<String_t>()) {
7427 return getExportKey(str);
7428 }
7429 }
7430 }
7431 }
7432 return std::nullopt;
7433 }
7434
7366 void transformExport(Export_t* exportNode, str_list& out) { 7435 void transformExport(Export_t* exportNode, str_list& out) {
7367 auto x = exportNode; 7436 auto x = exportNode;
7368 if (_scopes.size() > 1) { 7437 if (_scopes.size() > 1) {
7369 throw CompileError("can not do module export outside the root block"sv, exportNode); 7438 throw CompileError("can not do module export outside the root block"sv, exportNode);
7370 } 7439 }
7371 if (exportNode->assign) { 7440 if (exportNode->assign) {
7372 auto expList = exportNode->target.to<ExpList_t>(); 7441 if (ast_is<Exp_t, DotChainItem_t>(exportNode->target)) {
7373 if (expList->exprs.size() != exportNode->assign->values.size()) { 7442 if (auto name = getExportKey(exportNode->target)) {
7374 throw CompileError("left and right expressions must be matched in export statement"sv, x); 7443 if (auto dotChain = exportNode->target.as<DotChainItem_t>();
7375 } 7444 dotChain && dotChain->name.is<Metamethod_t>()) {
7376 for (auto _exp : expList->exprs.objects()) { 7445 auto nameStr = name.value();
7377 auto exp = static_cast<Exp_t*>(_exp); 7446 if (_exportedMetaKeys.find(nameStr) != _exportedMetaKeys.end()) {
7378 if (!variableFrom(exp) && !exp->getByPath<UnaryExp_t, Value_t, SimpleValue_t, TableLit_t>() && !exp->getByPath<UnaryExp_t, Value_t, SimpleTable_t>()) { 7447 throw CompileError("export module metamethod key \"" + nameStr + "\" duplicated"s, dotChain->name);
7379 throw CompileError("left hand expressions must be variables in export statement"sv, x); 7448 } else {
7449 _exportedMetaKeys.insert(nameStr);
7450 }
7451 } else {
7452 auto nameStr = name.value();
7453 if (_exportedKeys.find(nameStr) != _exportedKeys.end()) {
7454 throw CompileError("export module key \"" + nameStr + "\" duplicated"s, exportNode->target);
7455 } else {
7456 _exportedKeys.insert(nameStr);
7457 }
7458 }
7380 } 7459 }
7381 } 7460 auto newChain = x->new_ptr<ChainValue_t>();
7382 auto assignment = x->new_ptr<ExpListAssign_t>(); 7461 auto callable = toAst<Callable_t>(_info.moduleName, x);
7383 assignment->expList.set(expList); 7462 newChain->items.push_front(callable);
7384 assignment->action.set(exportNode->assign); 7463 newChain->items.push_back(exportNode->target);
7385 transformAssignment(assignment, out); 7464 auto exp = newExp(newChain, x);
7386 str_list names = transformAssignDefs(expList, DefOp::Get); 7465 auto expList = x->new_ptr<ExpList_t>();
7387 auto info = extractDestructureInfo(assignment, true, false); 7466 expList->exprs.push_back(exp);
7388 if (!info.destructures.empty()) { 7467 auto assignment = x->new_ptr<ExpListAssign_t>();
7389 for (const auto& destruct : info.destructures) 7468 assignment->expList.set(expList);
7390 for (const auto& item : destruct.items) 7469 assignment->action.set(exportNode->assign);
7391 if (!item.targetVar.empty()) 7470 transformAssignment(assignment, out);
7392 names.push_back(item.targetVar);
7393 }
7394 if (_info.exportDefault) {
7395 out.back().append(indent() + _info.moduleName + " = "s + names.back() + nlr(exportNode));
7396 } else { 7471 } else {
7397 str_list lefts, rights; 7472 auto expList = exportNode->target.to<ExpList_t>();
7398 for (const auto& name : names) { 7473 if (expList->exprs.size() != exportNode->assign->values.size()) {
7399 lefts.push_back(_info.moduleName + "[\""s + name + "\"]"s); 7474 throw CompileError("left and right expressions must be matched in export statement"sv, x);
7400 rights.push_back(name); 7475 }
7476 for (auto _exp : expList->exprs.objects()) {
7477 auto exp = static_cast<Exp_t*>(_exp);
7478 if (!variableFrom(exp) && !exp->getByPath<UnaryExp_t, Value_t, SimpleValue_t, TableLit_t>() && !exp->getByPath<UnaryExp_t, Value_t, SimpleTable_t>()) {
7479 throw CompileError("left hand expressions must be variables in export statement"sv, x);
7480 }
7481 }
7482 auto assignment = x->new_ptr<ExpListAssign_t>();
7483 assignment->expList.set(expList);
7484 assignment->action.set(exportNode->assign);
7485 transformAssignment(assignment, out);
7486 str_list names = transformAssignDefs(expList, DefOp::Get);
7487 auto info = extractDestructureInfo(assignment, true, false);
7488 if (!info.destructures.empty()) {
7489 for (const auto& destruct : info.destructures)
7490 for (const auto& item : destruct.items)
7491 if (!item.targetVar.empty())
7492 names.push_back(item.targetVar);
7493 }
7494 if (_info.exportDefault) {
7495 out.back().append(indent() + _info.moduleName + " = "s + names.back() + nlr(exportNode));
7496 } else {
7497 str_list lefts, rights;
7498 for (const auto& name : names) {
7499 if (_exportedKeys.find(name) != _exportedKeys.end()) {
7500 throw CompileError("export module key \"" + name + "\" duplicated"s, x);
7501 } else {
7502 _exportedKeys.insert(name);
7503 }
7504 lefts.push_back(_info.moduleName + "[\""s + name + "\"]"s);
7505 rights.push_back(name);
7506 }
7507 out.back().append(indent() + join(lefts, ", "sv) + " = "s + join(rights, ", "sv) + nlr(exportNode));
7401 } 7508 }
7402 out.back().append(indent() + join(lefts, ", "sv) + " = "s + join(rights, ", "sv) + nlr(exportNode));
7403 } 7509 }
7404 } else { 7510 } else {
7405 if (auto macro = exportNode->target.as<Macro_t>()) { 7511 if (auto macro = exportNode->target.as<Macro_t>()) {