aboutsummaryrefslogtreecommitdiff
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
parenta8c4737494818e6591cac2191bf3a49cbe990173 (diff)
downloadyuescript-78d5e6f44c06ac24aee667b5f9a9e642dcc6208d.tar.gz
yuescript-78d5e6f44c06ac24aee667b5f9a9e642dcc6208d.tar.bz2
yuescript-78d5e6f44c06ac24aee667b5f9a9e642dcc6208d.zip
fix issue #133.
-rw-r--r--spec/inputs/export.yue6
-rw-r--r--spec/inputs/syntax.yue2
-rw-r--r--spec/inputs/try-catch.yue3
-rw-r--r--spec/outputs/assign.lua6
-rw-r--r--spec/outputs/attrib.lua18
-rw-r--r--spec/outputs/do.lua6
-rw-r--r--spec/outputs/export.lua13
-rw-r--r--spec/outputs/syntax.lua8
-rw-r--r--spec/outputs/try-catch.lua11
-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
13 files changed, 240 insertions, 92 deletions
diff --git a/spec/inputs/export.yue b/spec/inputs/export.yue
index 15ffbcb..66e6736 100644
--- a/spec/inputs/export.yue
+++ b/spec/inputs/export.yue
@@ -29,7 +29,7 @@ export cbVal = do
29 (x)<- f 29 (x)<- f
30 return x h 30 return x h
31 31
32export y = -> 32export yy = ->
33 h = 100 33 h = 100
34 k = 100 34 k = 100
35 35
@@ -84,3 +84,7 @@ export v2 = 2
84export v3 = class v4 84export v3 = class v4
85v5 = 5 85v5 = 5
86 86
87export.<"abc"> = 1
88export.<name> = "export"
89export.<call> = => {}
90export["a-b-c-x"] = 123
diff --git a/spec/inputs/syntax.yue b/spec/inputs/syntax.yue
index 4f693d4..d60a145 100644
--- a/spec/inputs/syntax.yue
+++ b/spec/inputs/syntax.yue
@@ -214,7 +214,7 @@ tb[] = 2
214tb[] = 3 214tb[] = 3
215 215
216x = 0 216x = 0
217_ = (if ntype(v) == "fndef" then x += 1) for v in *values 217_ = (if ntype(v) == "fndef" then x + 1) for v in *values
218 218
219 219
220hello = 220hello =
diff --git a/spec/inputs/try-catch.yue b/spec/inputs/try-catch.yue
index 7287c33..e38cbef 100644
--- a/spec/inputs/try-catch.yue
+++ b/spec/inputs/try-catch.yue
@@ -23,6 +23,7 @@ try tb.func
23try tb.func! 23try tb.func!
24try tb.func() 24try tb.func()
25try (tb.func!) 25try (tb.func!)
26try (tb\func(1, 2, 3))
26 27
27try tb.func 1 28try tb.func 1
28try tb.func(1) 29try tb.func(1)
@@ -32,7 +33,7 @@ catch err
32 print err) 33 print err)
33 print "OK" 34 print "OK"
34 35
35if try func 1 36if try (func 1)
36catch err 37catch err
37 print err 38 print err
38 print "OK" 39 print "OK"
diff --git a/spec/outputs/assign.lua b/spec/outputs/assign.lua
index d939769..228e859 100644
--- a/spec/outputs/assign.lua
+++ b/spec/outputs/assign.lua
@@ -36,10 +36,10 @@ local x
36do 36do
37 local f = getHandler() 37 local f = getHandler()
38 if f then 38 if f then
39 x = ((function() 39 do
40 f() 40 f()
41 return 123 41 x = 123
42 end)()) 42 end
43 end 43 end
44end 44end
45return _(function() 45return _(function()
diff --git a/spec/outputs/attrib.lua b/spec/outputs/attrib.lua
index aed549d..fbac28e 100644
--- a/spec/outputs/attrib.lua
+++ b/spec/outputs/attrib.lua
@@ -32,21 +32,17 @@ do
32 end)() 32 end)()
33 local b <close> = (function() 33 local b <close> = (function()
34 if not false then 34 if not false then
35 return ((function() 35 if x then
36 if x then 36 return 1
37 return 1 37 end
38 end
39 end)())
40 end 38 end
41 end)() 39 end)()
42 local c <const> = (function() 40 local c <const> = (function()
43 if true then 41 if true then
44 return ((function() 42 local _exp_0 = x
45 local _exp_0 = x 43 if "abc" == _exp_0 then
46 if "abc" == _exp_0 then 44 return 998
47 return 998 45 end
48 end
49 end)())
50 end 46 end
51 end)() 47 end)()
52 local d <close> = (function() 48 local d <close> = (function()
diff --git a/spec/outputs/do.lua b/spec/outputs/do.lua
index 96d1022..6473e03 100644
--- a/spec/outputs/do.lua
+++ b/spec/outputs/do.lua
@@ -32,10 +32,10 @@ local t = {
32} 32}
33return function(y, k) 33return function(y, k)
34 if y == nil then 34 if y == nil then
35 y = ((function() 35 do
36 x = 10 + 2 36 x = 10 + 2
37 return x 37 y = x
38 end)()) 38 end
39 end 39 end
40 if k == nil then 40 if k == nil then
41 do 41 do
diff --git a/spec/outputs/export.lua b/spec/outputs/export.lua
index 962f18c..f1beeee 100644
--- a/spec/outputs/export.lua
+++ b/spec/outputs/export.lua
@@ -1,4 +1,4 @@
1local _module_0 = { } 1local _module_0 = setmetatable({ }, { })
2local a, b, c = 223, 343, 123 2local a, b, c = 223, 343, 123
3_module_0["a"], _module_0["b"], _module_0["c"] = a, b, c 3_module_0["a"], _module_0["b"], _module_0["c"] = a, b, c
4local cool = "dad" 4local cool = "dad"
@@ -62,11 +62,12 @@ do
62 end) 62 end)
63end 63end
64_module_0["cbVal"] = cbVal 64_module_0["cbVal"] = cbVal
65y = function() 65local yy
66yy = function()
66 local h = 100 67 local h = 100
67 local k = 100 68 local k = 100
68end 69end
69_module_0["y"] = y 70_module_0["yy"] = yy
70do 71do
71 local _exp_0 = h 72 local _exp_0 = h
72 if 100 == _exp_0 or 150 == _exp_0 then 73 if 100 == _exp_0 or 150 == _exp_0 then
@@ -322,4 +323,10 @@ do
322end 323end
323_module_0["v3"] = v3 324_module_0["v3"] = v3
324v5 = 5 325v5 = 5
326getmetatable(_module_0)["abc"] = 1
327getmetatable(_module_0).__name = "export"
328getmetatable(_module_0).__call = function(self)
329 return { }
330end
331_module_0["a-b-c-x"] = 123
325return _module_0 332return _module_0
diff --git a/spec/outputs/syntax.lua b/spec/outputs/syntax.lua
index 990083f..2afadbb 100644
--- a/spec/outputs/syntax.lua
+++ b/spec/outputs/syntax.lua
@@ -239,11 +239,9 @@ x = 0
239local _list_0 = values 239local _list_0 = values
240for _index_0 = 1, #_list_0 do 240for _index_0 = 1, #_list_0 do
241 local v = _list_0[_index_0] 241 local v = _list_0[_index_0]
242 _ = ((function() 242 if ntype(v) == "fndef" then
243 if ntype(v) == "fndef" then 243 _ = x + 1
244 x = x + 1 244 end
245 end
246 end)())
247end 245end
248hello = { 246hello = {
249 something = world, 247 something = world,
diff --git a/spec/outputs/try-catch.lua b/spec/outputs/try-catch.lua
index 692905e..129d412 100644
--- a/spec/outputs/try-catch.lua
+++ b/spec/outputs/try-catch.lua
@@ -21,7 +21,14 @@ end
21pcall(tb.func) 21pcall(tb.func)
22pcall(tb.func) 22pcall(tb.func)
23pcall(tb.func) 23pcall(tb.func)
24pcall((tb.func())) 24pcall((tb.func))
25pcall(((function()
26 local _base_0 = tb
27 local _fn_0 = _base_0.func
28 return _fn_0 and function(...)
29 return _fn_0(_base_0, ...)
30 end
31end)()), 1, 2, 3)
25pcall(tb.func, 1) 32pcall(tb.func, 1)
26pcall(tb.func, 1) 33pcall(tb.func, 1)
27if (xpcall(func, function(err) 34if (xpcall(func, function(err)
@@ -29,7 +36,7 @@ if (xpcall(func, function(err)
29end, 1)) then 36end, 1)) then
30 print("OK") 37 print("OK")
31end 38end
32if xpcall(func, function(err) 39if xpcall((func), function(err)
33 return print(err) 40 return print(err)
34end, 1) then 41end, 1) then
35 print("OK") 42 print("OK")
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);