diff options
author | Li Jin <dragon-fly@qq.com> | 2023-05-17 09:19:20 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2023-05-17 09:19:20 +0800 |
commit | 78d5e6f44c06ac24aee667b5f9a9e642dcc6208d (patch) | |
tree | 78913f601c44a1d85e275a30e4a1272fee00c4cb | |
parent | a8c4737494818e6591cac2191bf3a49cbe990173 (diff) | |
download | yuescript-78d5e6f44c06ac24aee667b5f9a9e642dcc6208d.tar.gz yuescript-78d5e6f44c06ac24aee667b5f9a9e642dcc6208d.tar.bz2 yuescript-78d5e6f44c06ac24aee667b5f9a9e642dcc6208d.zip |
fix issue #133.
-rw-r--r-- | spec/inputs/export.yue | 6 | ||||
-rw-r--r-- | spec/inputs/syntax.yue | 2 | ||||
-rw-r--r-- | spec/inputs/try-catch.yue | 3 | ||||
-rw-r--r-- | spec/outputs/assign.lua | 6 | ||||
-rw-r--r-- | spec/outputs/attrib.lua | 18 | ||||
-rw-r--r-- | spec/outputs/do.lua | 6 | ||||
-rw-r--r-- | spec/outputs/export.lua | 13 | ||||
-rw-r--r-- | spec/outputs/syntax.lua | 8 | ||||
-rw-r--r-- | spec/outputs/try-catch.lua | 11 | ||||
-rw-r--r-- | src/yuescript/yue_ast.h | 14 | ||||
-rw-r--r-- | src/yuescript/yue_compiler.cpp | 170 | ||||
-rw-r--r-- | src/yuescript/yue_parser.cpp | 71 | ||||
-rw-r--r-- | src/yuescript/yue_parser.h | 4 |
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 | ||
32 | export y = -> | 32 | export yy = -> |
33 | h = 100 | 33 | h = 100 |
34 | k = 100 | 34 | k = 100 |
35 | 35 | ||
@@ -84,3 +84,7 @@ export v2 = 2 | |||
84 | export v3 = class v4 | 84 | export v3 = class v4 |
85 | v5 = 5 | 85 | v5 = 5 |
86 | 86 | ||
87 | export.<"abc"> = 1 | ||
88 | export.<name> = "export" | ||
89 | export.<call> = => {} | ||
90 | export["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 | |||
214 | tb[] = 3 | 214 | tb[] = 3 |
215 | 215 | ||
216 | x = 0 | 216 | x = 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 | ||
220 | hello = | 220 | hello = |
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 | |||
23 | try tb.func! | 23 | try tb.func! |
24 | try tb.func() | 24 | try tb.func() |
25 | try (tb.func!) | 25 | try (tb.func!) |
26 | try (tb\func(1, 2, 3)) | ||
26 | 27 | ||
27 | try tb.func 1 | 28 | try tb.func 1 |
28 | try tb.func(1) | 29 | try tb.func(1) |
@@ -32,7 +33,7 @@ catch err | |||
32 | print err) | 33 | print err) |
33 | print "OK" | 34 | print "OK" |
34 | 35 | ||
35 | if try func 1 | 36 | if try (func 1) |
36 | catch err | 37 | catch 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 | |||
36 | do | 36 | do |
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 |
44 | end | 44 | end |
45 | return _(function() | 45 | return _(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 | } |
33 | return function(y, k) | 33 | return 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 @@ | |||
1 | local _module_0 = { } | 1 | local _module_0 = setmetatable({ }, { }) |
2 | local a, b, c = 223, 343, 123 | 2 | local 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 |
4 | local cool = "dad" | 4 | local cool = "dad" |
@@ -62,11 +62,12 @@ do | |||
62 | end) | 62 | end) |
63 | end | 63 | end |
64 | _module_0["cbVal"] = cbVal | 64 | _module_0["cbVal"] = cbVal |
65 | y = function() | 65 | local yy |
66 | yy = function() | ||
66 | local h = 100 | 67 | local h = 100 |
67 | local k = 100 | 68 | local k = 100 |
68 | end | 69 | end |
69 | _module_0["y"] = y | 70 | _module_0["yy"] = yy |
70 | do | 71 | do |
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 | |||
322 | end | 323 | end |
323 | _module_0["v3"] = v3 | 324 | _module_0["v3"] = v3 |
324 | v5 = 5 | 325 | v5 = 5 |
326 | getmetatable(_module_0)["abc"] = 1 | ||
327 | getmetatable(_module_0).__name = "export" | ||
328 | getmetatable(_module_0).__call = function(self) | ||
329 | return { } | ||
330 | end | ||
331 | _module_0["a-b-c-x"] = 123 | ||
325 | return _module_0 | 332 | return _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 | |||
239 | local _list_0 = values | 239 | local _list_0 = values |
240 | for _index_0 = 1, #_list_0 do | 240 | for _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)()) | ||
247 | end | 245 | end |
248 | hello = { | 246 | hello = { |
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 | |||
21 | pcall(tb.func) | 21 | pcall(tb.func) |
22 | pcall(tb.func) | 22 | pcall(tb.func) |
23 | pcall(tb.func) | 23 | pcall(tb.func) |
24 | pcall((tb.func())) | 24 | pcall((tb.func)) |
25 | pcall(((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 | ||
31 | end)()), 1, 2, 3) | ||
25 | pcall(tb.func, 1) | 32 | pcall(tb.func, 1) |
26 | pcall(tb.func, 1) | 33 | pcall(tb.func, 1) |
27 | if (xpcall(func, function(err) | 34 | if (xpcall(func, function(err) |
@@ -29,7 +36,7 @@ if (xpcall(func, function(err) | |||
29 | end, 1)) then | 36 | end, 1)) then |
30 | print("OK") | 37 | print("OK") |
31 | end | 38 | end |
32 | if xpcall(func, function(err) | 39 | if xpcall((func), function(err) |
33 | return print(err) | 40 | return print(err) |
34 | end, 1) then | 41 | end, 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 | ||
523 | AST_NODE(SimpleValue) | 523 | AST_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) |
532 | AST_END(SimpleValue, "simple_value"sv) | 532 | AST_END(SimpleValue, "simple_value"sv) |
533 | 533 | ||
@@ -708,7 +708,7 @@ class Macro_t; | |||
708 | 708 | ||
709 | AST_NODE(Export) | 709 | AST_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) |
714 | AST_END(Export, "export"sv) | 714 | AST_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 | ||
75 | const std::string_view version = "0.16.3"sv; | 75 | const std::string_view version = "0.16.4"sv; |
76 | const std::string_view extension = "yue"sv; | 76 | const std::string_view extension = "yue"sv; |
77 | 77 | ||
78 | class CompileError : public std::logic_error { | 78 | class 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); |