aboutsummaryrefslogtreecommitdiff
path: root/src
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
parenta8c4737494818e6591cac2191bf3a49cbe990173 (diff)
downloadyuescript-78d5e6f44c06ac24aee667b5f9a9e642dcc6208d.tar.gz
yuescript-78d5e6f44c06ac24aee667b5f9a9e642dcc6208d.tar.bz2
yuescript-78d5e6f44c06ac24aee667b5f9a9e642dcc6208d.zip
fix issue #133.
Diffstat (limited to 'src')
-rw-r--r--src/yuescript/yue_ast.h14
-rw-r--r--src/yuescript/yue_compiler.cpp170
-rw-r--r--src/yuescript/yue_parser.cpp71
-rw-r--r--src/yuescript/yue_parser.h4
4 files changed, 197 insertions, 62 deletions
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h
index 47ddb0b..65008fb 100644
--- a/src/yuescript/yue_ast.h
+++ b/src/yuescript/yue_ast.h
@@ -522,12 +522,12 @@ class FunLit_t;
522 522
523AST_NODE(SimpleValue) 523AST_NODE(SimpleValue)
524 ast_sel<true, 524 ast_sel<true,
525 TableLit_t, ConstValue_t, 525 TableLit_t, ConstValue_t,
526 If_t, Switch_t, With_t, ClassDecl_t, 526 If_t, Switch_t, With_t, ClassDecl_t,
527 ForEach_t, For_t, While_t, Do_t, Try_t, 527 ForEach_t, For_t, While_t, Do_t, Try_t,
528 UnaryValue_t, 528 UnaryValue_t,
529 TblComprehension_t, Comprehension_t, 529 TblComprehension_t, Comprehension_t,
530 FunLit_t, Num_t, VarArg_t> value; 530 FunLit_t, Num_t, VarArg_t> value;
531 AST_MEMBER(SimpleValue, &value) 531 AST_MEMBER(SimpleValue, &value)
532AST_END(SimpleValue, "simple_value"sv) 532AST_END(SimpleValue, "simple_value"sv)
533 533
@@ -708,7 +708,7 @@ class Macro_t;
708 708
709AST_NODE(Export) 709AST_NODE(Export)
710 ast_ptr<false, ExportDefault_t> def; 710 ast_ptr<false, ExportDefault_t> def;
711 ast_sel<true, ExpList_t, Exp_t, Macro_t> target; 711 ast_sel<true, ExpList_t, Exp_t, Macro_t, DotChainItem_t> target;
712 ast_ptr<false, Assign_t> assign; 712 ast_ptr<false, Assign_t> assign;
713 AST_MEMBER(Export, &def, &target, &assign) 713 AST_MEMBER(Export, &def, &target, &assign)
714AST_END(Export, "export"sv) 714AST_END(Export, "export"sv)
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>()) {
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp
index f215ee4..99fea0a 100644
--- a/src/yuescript/yue_parser.cpp
+++ b/src/yuescript/yue_parser.cpp
@@ -93,6 +93,11 @@ YueParser::YueParser() {
93 return false; 93 return false;
94 }); 94 });
95 95
96 export_expression_error = pl::user(true_(), [](const item_t& item) {
97 throw ParserError("invalid export expression"sv, item.begin);
98 return false;
99 });
100
96 #define ensure(patt, finally) ((patt) >> (finally) | (finally) >> cut) 101 #define ensure(patt, finally) ((patt) >> (finally) | (finally) >> cut)
97 102
98 #define key(str) (expr(str) >> not_alpha_num) 103 #define key(str) (expr(str) >> not_alpha_num)
@@ -666,29 +671,48 @@ YueParser::YueParser() {
666 State* st = reinterpret_cast<State*>(item.user_data); 671 State* st = reinterpret_cast<State*>(item.user_data);
667 st->exportCount++; 672 st->exportCount++;
668 return true; 673 return true;
669 }) >> (pl::user(space >> ExportDefault >> space >> Exp, [](const item_t& item) { 674 }) >> (
670 State* st = reinterpret_cast<State*>(item.user_data); 675 pl::user(space >> ExportDefault >> space >> Exp, [](const item_t& item) {
671 if (st->exportDefault) { 676 State* st = reinterpret_cast<State*>(item.user_data);
672 throw ParserError("export default has already been declared"sv, item.begin); 677 if (st->exportDefault) {
673 } 678 throw ParserError("export default has already been declared"sv, item.begin);
674 if (st->exportCount > 1) { 679 }
675 throw ParserError("there are items already being exported"sv, item.begin); 680 if (st->exportCount > 1) {
676 } 681 throw ParserError("there are items already being exported"sv, item.begin);
677 st->exportDefault = true; 682 }
678 return true; 683 st->exportDefault = true;
679 }) 684 return true;
680 | (not_(space >> ExportDefault) >> pl::user(true_(), [](const item_t& item) { 685 }) |
681 State* st = reinterpret_cast<State*>(item.user_data); 686 not_(space >> ExportDefault) >> pl::user(true_(), [](const item_t& item) {
682 if (st->exportDefault && st->exportCount > 1) { 687 State* st = reinterpret_cast<State*>(item.user_data);
683 throw ParserError("can not export any more items when 'export default' is declared"sv, item.begin); 688 if (st->exportDefault && st->exportCount > 1) {
684 } 689 throw ParserError("can not export any more items when 'export default' is declared"sv, item.begin);
685 return true; 690 }
686 }) >> space >> ExpList >> -(space >> Assign)) 691 return true;
687 | space >> pl::user(Macro, [](const item_t& item) { 692 }) >> (
688 State* st = reinterpret_cast<State*>(item.user_data); 693 and_(set(".[")) >> ((pl::user(and_('.' >> Metatable), [](const item_t& item) {
689 st->exportMacro = true; 694 State* st = reinterpret_cast<State*>(item.user_data);
690 return true; 695 if (st->exportMetatable) {
691 })) >> not_(space >> StatementAppendix); 696 throw ParserError("module metatable duplicated"sv, item.begin);
697 }
698 if (st->exportMetamethod) {
699 throw ParserError("metatable should be exported before metamethod"sv, item.begin);
700 }
701 st->exportMetatable = true;
702 return true;
703 }) | pl::user(and_(".<"), [](const item_t& item) {
704 State* st = reinterpret_cast<State*>(item.user_data);
705 st->exportMetamethod = true;
706 return true;
707 }) | true_()) >> (DotChainItem | index) >> space >> Assign | export_expression_error) |
708 space >> ExpList >> -(space >> Assign)
709 ) |
710 space >> pl::user(Macro, [](const item_t& item) {
711 State* st = reinterpret_cast<State*>(item.user_data);
712 st->exportMacro = true;
713 return true;
714 })
715 ) >> not_(space >> StatementAppendix);
692 716
693 VariablePair = ':' >> Variable; 717 VariablePair = ':' >> Variable;
694 718
@@ -897,6 +921,7 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) {
897 res.moduleName = std::move(state.moduleName); 921 res.moduleName = std::move(state.moduleName);
898 res.exportDefault = state.exportDefault; 922 res.exportDefault = state.exportDefault;
899 res.exportMacro = state.exportMacro; 923 res.exportMacro = state.exportMacro;
924 res.exportMetatable = !state.exportMetatable && state.exportMetamethod;
900 } 925 }
901 } catch (const ParserError& err) { 926 } catch (const ParserError& err) {
902 res.error = {err.what(), err.line, err.col}; 927 res.error = {err.what(), err.line, err.col};
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h
index 31134e1..59a16a8 100644
--- a/src/yuescript/yue_parser.h
+++ b/src/yuescript/yue_parser.h
@@ -37,6 +37,7 @@ struct ParseInfo {
37 std::unique_ptr<input> codes; 37 std::unique_ptr<input> codes;
38 bool exportDefault = false; 38 bool exportDefault = false;
39 bool exportMacro = false; 39 bool exportMacro = false;
40 bool exportMetatable = false;
40 std::string moduleName; 41 std::string moduleName;
41 std::string errorMessage(std::string_view msg, int errLine, int errCol) const; 42 std::string errorMessage(std::string_view msg, int errLine, int errCol) const;
42}; 43};
@@ -97,6 +98,8 @@ protected:
97 } 98 }
98 bool exportDefault = false; 99 bool exportDefault = false;
99 bool exportMacro = false; 100 bool exportMacro = false;
101 bool exportMetatable = false;
102 bool exportMetamethod = false;
100 int exportCount = 0; 103 int exportCount = 0;
101 int moduleFix = 0; 104 int moduleFix = 0;
102 int expLevel = 0; 105 int expLevel = 0;
@@ -129,6 +132,7 @@ private:
129 NONE_AST_RULE(indentation_error); 132 NONE_AST_RULE(indentation_error);
130 NONE_AST_RULE(braces_expression_error); 133 NONE_AST_RULE(braces_expression_error);
131 NONE_AST_RULE(brackets_expression_error); 134 NONE_AST_RULE(brackets_expression_error);
135 NONE_AST_RULE(export_expression_error);
132 136
133 NONE_AST_RULE(inc_exp_level); 137 NONE_AST_RULE(inc_exp_level);
134 NONE_AST_RULE(dec_exp_level); 138 NONE_AST_RULE(dec_exp_level);