aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xdoc/docs/doc/README.md68
-rw-r--r--spec/inputs/return.yue13
-rw-r--r--spec/inputs/tables.yue23
-rw-r--r--spec/outputs/return.lua24
-rw-r--r--spec/outputs/tables.lua61
-rwxr-xr-xsrc/yuescript/yue_ast.h6
-rwxr-xr-xsrc/yuescript/yue_compiler.cpp351
-rwxr-xr-xsrc/yuescript/yue_parser.cpp9
-rwxr-xr-xsrc/yuescript/yue_parser.h1
9 files changed, 407 insertions, 149 deletions
diff --git a/doc/docs/doc/README.md b/doc/docs/doc/README.md
index adff569..65266cb 100755
--- a/doc/docs/doc/README.md
+++ b/doc/docs/doc/README.md
@@ -118,14 +118,14 @@ export yuescript = "ζœˆδΉ‹θ„šζœ¬"
118 118
119 Use Yuescript module in Lua: 119 Use Yuescript module in Lua:
120 120
121* **Case 1** 121* **Case 1**
122Require "your_yuescript_entry.yue" in Lua. 122Require "your_yuescript_entry.yue" in Lua.
123```Lua 123```Lua
124require("yue")("your_yuescript_entry") 124require("yue")("your_yuescript_entry")
125``` 125```
126 And this code still works when you compile "your_yuescript_entry.yue" to "your_yuescript_entry.lua" in the same path. In the rest Yuescript files just use the normal **require** or **import**. The code line numbers in error messages will also be handled correctly. 126 And this code still works when you compile "your_yuescript_entry.yue" to "your_yuescript_entry.lua" in the same path. In the rest Yuescript files just use the normal **require** or **import**. The code line numbers in error messages will also be handled correctly.
127 127
128* **Case 2** 128* **Case 2**
129Require Yuescript module and rewite message by hand. 129Require Yuescript module and rewite message by hand.
130```lua 130```lua
131local yue = require("yue") 131local yue = require("yue")
@@ -136,7 +136,7 @@ end, function(err)
136end) 136end)
137``` 137```
138 138
139* **Case 3** 139* **Case 3**
140Use the Yuescript compiler function in Lua. 140Use the Yuescript compiler function in Lua.
141```lua 141```lua
142local yue = require("yue") 142local yue = require("yue")
@@ -174,12 +174,12 @@ Usage: yue [options|files|directories] ...
174 Execute without options to enter REPL, type symbol '$' 174 Execute without options to enter REPL, type symbol '$'
175 in a single line to start/stop multi-line mode 175 in a single line to start/stop multi-line mode
176``` 176```
177  Use cases: 177  Use cases:
178  Recursively compile every Yuescript file with extension **.yue** under current path: **yue .** 178  Recursively compile every Yuescript file with extension **.yue** under current path: **yue .**
179  Compile and save results to a target path: **yue -t /target/path/ .** 179  Compile and save results to a target path: **yue -t /target/path/ .**
180  Compile and reserve debug info: **yue -l .** 180  Compile and reserve debug info: **yue -l .**
181  Compile and generate minified codes: **yue -m .** 181  Compile and generate minified codes: **yue -m .**
182  Execute raw codes: **yue -e 'print 123'** 182  Execute raw codes: **yue -e 'print 123'**
183  Execute a Yuescript file: **yue -e main.yue** 183  Execute a Yuescript file: **yue -e main.yue**
184 184
185## Macro 185## Macro
@@ -606,6 +606,45 @@ tb =
606</pre> 606</pre>
607</YueDisplay> 607</YueDisplay>
608 608
609### Spread Table
610
611You can concatenate array tables or hash tables using spread operator `...` before expressions in table literals.
612
613```moonscript
614parts =
615 * "shoulders"
616 * "knees"
617lyrics =
618 * "head"
619 * ...parts
620 * "and"
621 * "toes"
622
623copy = {...other}
624
625a = {1, 2, 3, x: 1}
626b = {4, 5, y: 1}
627merge = {...a, ...b}
628```
629<YueDisplay>
630<pre>
631parts =
632 * "shoulders"
633 * "knees"
634lyrics =
635 * "head"
636 * ...parts
637 * "and"
638 * "toes"
639
640copy = {...other}
641
642a = {1, 2, 3, x: 1}
643a = {4, 5, y: 1}
644merge = {...a, ...b}
645</pre>
646</YueDisplay>
647
609## Module 648## Module
610 649
611### Import 650### Import
@@ -981,6 +1020,17 @@ You can write default values while doing destructuring like:
981</pre> 1020</pre>
982</YueDisplay> 1021</YueDisplay>
983 1022
1023You can use `_` as placeholder when doing a list destructuring:
1024
1025```moonscript
1026{_, two, _, four} = items
1027```
1028<YueDisplay>
1029<pre>
1030{_, two, _, four} = items
1031</pre>
1032</YueDisplay>
1033
984### Destructuring In Other Places 1034### Destructuring In Other Places
985 1035
986Destructuring can also show up in places where an assignment implicitly takes place. An example of this is a for loop: 1036Destructuring can also show up in places where an assignment implicitly takes place. An example of this is a for loop:
diff --git a/spec/inputs/return.yue b/spec/inputs/return.yue
index f170ffd..96fa0cd 100644
--- a/spec/inputs/return.yue
+++ b/spec/inputs/return.yue
@@ -49,6 +49,19 @@ do
49 else 49 else
50 b 50 b
51 51
52do
53 return
54 :value
55 itemA: 123
56 itemB: "abc"
57
58do
59 return
60 * 1
61 * 2
62 * ...three
63 * 4
64
52_ = -> a\b 65_ = -> a\b
53do a\b 66do a\b
54 67
diff --git a/spec/inputs/tables.yue b/spec/inputs/tables.yue
index 3a245a7..e1b9e1d 100644
--- a/spec/inputs/tables.yue
+++ b/spec/inputs/tables.yue
@@ -281,5 +281,28 @@ specializedB = {
281 else: false 281 else: false
282} 282}
283 283
284parts =
285 * "shoulders"
286 * "knees"
287
288lyrics =
289 * "head"
290 * ...parts
291 * "and"
292 * "toes"
293
294tbBlock =
295 sub:
296 :value
297 * ...items
298 * ...
299
300func
301 * ...items
302 :value
303 * ...
304 k: v
305 * ...
306
284nil 307nil
285 308
diff --git a/spec/outputs/return.lua b/spec/outputs/return.lua
index 0735b23..775ae11 100644
--- a/spec/outputs/return.lua
+++ b/spec/outputs/return.lua
@@ -86,6 +86,30 @@ do
86 end 86 end
87 end 87 end
88end 88end
89do
90 return {
91 value = value,
92 itemA = 123,
93 itemB = "abc"
94 }
95end
96do
97 local _tab_0 = {
98 1,
99 2
100 }
101 local _idx_0 = 1
102 for _key_0, _value_0 in pairs(three) do
103 if _idx_0 == _key_0 then
104 _tab_0[#_tab_0 + 1] = _value_0
105 _idx_0 = _idx_0 + 1
106 else
107 _tab_0[_key_0] = _value_0
108 end
109 end
110 _tab_0[#_tab_0 + 1] = 4
111 return _tab_0
112end
89_ = function() 113_ = function()
90 local _base_0 = a 114 local _base_0 = a
91 local _fn_0 = _base_0.b 115 local _fn_0 = _base_0.b
diff --git a/spec/outputs/tables.lua b/spec/outputs/tables.lua
index 165706d..1d28a43 100644
--- a/spec/outputs/tables.lua
+++ b/spec/outputs/tables.lua
@@ -527,4 +527,65 @@ do
527 _tab_0["else"] = false 527 _tab_0["else"] = false
528 specializedB = _tab_0 528 specializedB = _tab_0
529end 529end
530local parts = {
531 "shoulders",
532 "knees"
533}
534local lyrics
535do
536 local _tab_0 = {
537 "head"
538 }
539 local _idx_0 = 1
540 for _key_0, _value_0 in pairs(parts) do
541 if _idx_0 == _key_0 then
542 _tab_0[#_tab_0 + 1] = _value_0
543 _idx_0 = _idx_0 + 1
544 else
545 _tab_0[_key_0] = _value_0
546 end
547 end
548 _tab_0[#_tab_0 + 1] = "and"
549 _tab_0[#_tab_0 + 1] = "toes"
550 lyrics = _tab_0
551end
552local tbBlock = {
553 sub = (function(...)
554 local _tab_0 = {
555 value = value
556 }
557 local _idx_0 = 1
558 for _key_0, _value_0 in pairs(items) do
559 if _idx_0 == _key_0 then
560 _tab_0[#_tab_0 + 1] = _value_0
561 _idx_0 = _idx_0 + 1
562 else
563 _tab_0[_key_0] = _value_0
564 end
565 end
566 for _index_0 = 1, select('#', ...) do
567 _tab_0[#_tab_0 + 1] = select(_index_0, ...)
568 end
569 return _tab_0
570 end)(...)
571}
572func((function(...)
573 local _tab_0 = { }
574 local _idx_0 = 1
575 for _key_0, _value_0 in pairs(items) do
576 if _idx_0 == _key_0 then
577 _tab_0[#_tab_0 + 1] = _value_0
578 _idx_0 = _idx_0 + 1
579 else
580 _tab_0[_key_0] = _value_0
581 end
582 end
583 _tab_0.value = value
584 _tab_0[#_tab_0 + 1] = ...
585 _tab_0.k = v
586 for _index_0 = 1, select('#', ...) do
587 _tab_0[#_tab_0 + 1] = select(_index_0, ...)
588 end
589 return _tab_0
590end)(...))
530return nil 591return nil
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h
index ed6f7d2..06896b8 100755
--- a/src/yuescript/yue_ast.h
+++ b/src/yuescript/yue_ast.h
@@ -221,9 +221,11 @@ AST_NODE(ExpList)
221 AST_MEMBER(ExpList, &sep, &exprs) 221 AST_MEMBER(ExpList, &sep, &exprs)
222AST_END(ExpList) 222AST_END(ExpList)
223 223
224class TableBlock_t;
225
224AST_NODE(Return) 226AST_NODE(Return)
225 bool allowBlockMacroReturn = false; 227 bool allowBlockMacroReturn = false;
226 ast_ptr<false, ExpListLow_t> valueList; 228 ast_sel<false, TableBlock_t, ExpListLow_t> valueList;
227 AST_MEMBER(Return, &valueList) 229 AST_MEMBER(Return, &valueList)
228AST_END(Return) 230AST_END(Return)
229 231
@@ -628,7 +630,7 @@ AST_END(TableBlockIndent)
628 630
629AST_NODE(TableBlock) 631AST_NODE(TableBlock)
630 ast_ptr<true, Seperator_t> sep; 632 ast_ptr<true, Seperator_t> sep;
631 ast_sel_list<false, variable_pair_t, normal_pair_t, TableBlockIndent_t, Exp_t, TableBlock_t, default_pair_t, 633 ast_sel_list<false, variable_pair_t, normal_pair_t, TableBlockIndent_t, Exp_t, TableBlock_t, SpreadExp_t, default_pair_t,
632 meta_variable_pair_t, meta_normal_pair_t, meta_default_pair_t> values; 634 meta_variable_pair_t, meta_normal_pair_t, meta_default_pair_t> values;
633 AST_MEMBER(TableBlock, &sep, &values) 635 AST_MEMBER(TableBlock, &sep, &values)
634AST_END(TableBlock) 636AST_END(TableBlock)
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index 6a0fba6..476494e 100755
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -60,7 +60,7 @@ using namespace parserlib;
60 60
61typedef std::list<std::string> str_list; 61typedef std::list<std::string> str_list;
62 62
63const std::string_view version = "0.10.14"sv; 63const std::string_view version = "0.10.15"sv;
64const std::string_view extension = "yue"sv; 64const std::string_view extension = "yue"sv;
65 65
66class YueCompilerImpl { 66class YueCompilerImpl {
@@ -1355,10 +1355,20 @@ private:
1355 } 1355 }
1356 case id<TableLit_t>(): { 1356 case id<TableLit_t>(): {
1357 auto tableLit = static_cast<TableLit_t*>(value); 1357 auto tableLit = static_cast<TableLit_t*>(value);
1358 if (hasSpreadExp(tableLit)) { 1358 if (hasSpreadExp(tableLit->values.objects())) {
1359 auto expList = assignment->expList.get(); 1359 auto expList = assignment->expList.get();
1360 std::string preDefine = getPredefine(assignment); 1360 std::string preDefine = getPredefine(assignment);
1361 transformSpreadTableLit(tableLit, out, ExpUsage::Assignment, expList); 1361 transformSpreadTable(tableLit->values.objects(), out, ExpUsage::Assignment, expList);
1362 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1363 return;
1364 }
1365 }
1366 case id<TableBlock_t>(): {
1367 auto tableBlock = static_cast<TableBlock_t*>(value);
1368 if (hasSpreadExp(tableBlock->values.objects())) {
1369 auto expList = assignment->expList.get();
1370 std::string preDefine = getPredefine(assignment);
1371 transformSpreadTable(tableBlock->values.objects(), out, ExpUsage::Assignment, expList);
1362 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment)); 1372 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1363 return; 1373 return;
1364 } 1374 }
@@ -3239,7 +3249,7 @@ private:
3239 if (!target) target = returnNode; 3249 if (!target) target = returnNode;
3240 throw std::logic_error(_info.errorMessage("illegal return statement here"sv, target)); 3250 throw std::logic_error(_info.errorMessage("illegal return statement here"sv, target));
3241 } 3251 }
3242 if (auto valueList = returnNode->valueList.get()) { 3252 if (auto valueList = returnNode->valueList.as<ExpListLow_t>()) {
3243 if (valueList->exprs.size() == 1) { 3253 if (valueList->exprs.size() == 1) {
3244 auto exp = static_cast<Exp_t*>(valueList->exprs.back()); 3254 auto exp = static_cast<Exp_t*>(valueList->exprs.back());
3245 if (isPureBackcall(exp)) { 3255 if (isPureBackcall(exp)) {
@@ -3286,8 +3296,8 @@ private:
3286 return; 3296 return;
3287 case id<TableLit_t>(): { 3297 case id<TableLit_t>(): {
3288 auto tableLit = static_cast<TableLit_t*>(value); 3298 auto tableLit = static_cast<TableLit_t*>(value);
3289 if (hasSpreadExp(tableLit)) { 3299 if (hasSpreadExp(tableLit->values.objects())) {
3290 transformSpreadTableLit(tableLit, out, ExpUsage::Return); 3300 transformSpreadTable(tableLit->values.objects(), out, ExpUsage::Return);
3291 return; 3301 return;
3292 } 3302 }
3293 } 3303 }
@@ -3306,6 +3316,14 @@ private:
3306 transformExpListLow(valueList, temp); 3316 transformExpListLow(valueList, temp);
3307 out.push_back(indent() + "return "s + temp.back() + nlr(returnNode)); 3317 out.push_back(indent() + "return "s + temp.back() + nlr(returnNode));
3308 } 3318 }
3319 } else if (auto tableBlock = returnNode->valueList.as<TableBlock_t>()) {
3320 const auto& values = tableBlock->values.objects();
3321 if (hasSpreadExp(values)) {
3322 transformSpreadTable(values, out, ExpUsage::Return);
3323 } else {
3324 transformTable(values, out);
3325 out.back() = indent() + "return "s + out.back() + nlr(returnNode);
3326 }
3309 } else { 3327 } else {
3310 out.push_back(indent() + "return"s + nll(returnNode)); 3328 out.push_back(indent() + "return"s + nll(returnNode));
3311 } 3329 }
@@ -4495,23 +4513,15 @@ private:
4495 out.push_back(_parser.toString(num)); 4513 out.push_back(_parser.toString(num));
4496 } 4514 }
4497 4515
4498 bool hasSpreadExp(TableLit_t* table) { 4516 bool hasSpreadExp(const node_container& items) {
4499 for (auto item : table->values.objects()) { 4517 for (auto item : items) {
4500 if (ast_is<SpreadExp_t>(item)) return true; 4518 if (ast_is<SpreadExp_t>(item)) return true;
4501 } 4519 }
4502 return false; 4520 return false;
4503 } 4521 }
4504 4522
4505 void transformTableLit(TableLit_t* table, str_list& out) { 4523 void transformSpreadTable(const node_container& values, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
4506 if (hasSpreadExp(table)) { 4524 auto x = values.front();
4507 transformSpreadTableLit(table, out, ExpUsage::Closure);
4508 } else {
4509 transformTable(table, table->values.objects(), out);
4510 }
4511 }
4512
4513 void transformSpreadTableLit(TableLit_t* table, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
4514 auto x = table;
4515 switch (usage) { 4525 switch (usage) {
4516 case ExpUsage::Closure: 4526 case ExpUsage::Closure:
4517 _enableReturn.push(true); 4527 _enableReturn.push(true);
@@ -4527,19 +4537,19 @@ private:
4527 str_list temp; 4537 str_list temp;
4528 std::string tableVar = getUnusedName("_tab_"sv); 4538 std::string tableVar = getUnusedName("_tab_"sv);
4529 forceAddToScope(tableVar); 4539 forceAddToScope(tableVar);
4530 auto it = table->values.objects().begin(); 4540 auto it = values.begin();
4531 if (ast_is<SpreadExp_t>(*it)) { 4541 if (ast_is<SpreadExp_t>(*it)) {
4532 temp.push_back(indent() + "local "s + tableVar + " = { }"s + nll(x)); 4542 temp.push_back(indent() + "local "s + tableVar + " = { }"s + nll(x));
4533 } else { 4543 } else {
4534 auto initialTab = x->new_ptr<TableLit_t>(); 4544 auto initialTab = x->new_ptr<TableLit_t>();
4535 while (it != table->values.objects().end() && !ast_is<SpreadExp_t>(*it)) { 4545 while (it != values.end() && !ast_is<SpreadExp_t>(*it)) {
4536 initialTab->values.push_back(*it); 4546 initialTab->values.push_back(*it);
4537 ++it; 4547 ++it;
4538 } 4548 }
4539 transformTable(table, initialTab->values.objects(), temp); 4549 transformTable(initialTab->values.objects(), temp);
4540 temp.back() = indent() + "local "s + tableVar + " = "s + temp.back() + nll(*it); 4550 temp.back() = indent() + "local "s + tableVar + " = "s + temp.back() + nll(*it);
4541 } 4551 }
4542 for (; it != table->values.objects().end(); ++it) { 4552 for (; it != values.end(); ++it) {
4543 auto item = *it; 4553 auto item = *it;
4544 switch (item->getId()) { 4554 switch (item->getId()) {
4545 case id<SpreadExp_t>(): { 4555 case id<SpreadExp_t>(): {
@@ -4623,7 +4633,7 @@ private:
4623 case id<Exp_t>(): { 4633 case id<Exp_t>(): {
4624 bool lastVarArg = false; 4634 bool lastVarArg = false;
4625 BLOCK_START 4635 BLOCK_START
4626 BREAK_IF(item != table->values.back()); 4636 BREAK_IF(item != values.back());
4627 auto value = singleValueFrom(item); 4637 auto value = singleValueFrom(item);
4628 BREAK_IF(!value); 4638 BREAK_IF(!value);
4629 auto chainValue = value->item.as<ChainValue_t>(); 4639 auto chainValue = value->item.as<ChainValue_t>();
@@ -4644,6 +4654,66 @@ private:
4644 } 4654 }
4645 break; 4655 break;
4646 } 4656 }
4657 case id<TableBlockIndent_t>(): {
4658 auto tbIndent = static_cast<TableBlockIndent_t*>(item);
4659 auto tableBlock = item->new_ptr<TableBlock_t>();
4660 tableBlock->values.dup(tbIndent->values);
4661 auto assignment = toAst<ExpListAssign_t>(tableVar + "[]=nil"s, item);
4662 auto assign = assignment->action.to<Assign_t>();
4663 assign->values.clear();
4664 assign->values.push_back(tableBlock);
4665 transformAssignment(assignment, temp);
4666 break;
4667 }
4668 case id<TableBlock_t>(): {
4669 auto assignment = toAst<ExpListAssign_t>(tableVar + "[]=nil"s, item);
4670 auto assign = assignment->action.to<Assign_t>();
4671 assign->values.clear();
4672 assign->values.push_back(item);
4673 transformAssignment(assignment, temp);
4674 break;
4675 }
4676 case id<meta_variable_pair_t>(): {
4677 auto metaVarPair = static_cast<meta_variable_pair_t*>(item);
4678 auto nameStr = _parser.toString(metaVarPair->name);
4679 auto assignment = toAst<ExpListAssign_t>(tableVar + '.' + nameStr + "#="s + nameStr, item);
4680 transformAssignment(assignment, temp);
4681 break;
4682 }
4683 case id<meta_normal_pair_t>(): {
4684 auto metaNormalPair = static_cast<meta_normal_pair_t*>(item);
4685 auto assignment = toAst<ExpListAssign_t>(tableVar + "=nil"s, item);
4686 auto chainValue = singleValueFrom(ast_to<Exp_t>(assignment->expList->exprs.front()))->item.to<ChainValue_t>();
4687 auto key = metaNormalPair->key.get();
4688 switch (key->getId()) {
4689 case id<Name_t>(): {
4690 auto dotItem = x->new_ptr<DotChainItem_t>();
4691 dotItem->name.set(key);
4692 chainValue->items.push_back(dotItem);
4693 break;
4694 }
4695 case id<Exp_t>(): {
4696 auto dotItem = toAst<DotChainItem_t>(".#"sv, key);
4697 chainValue->items.push_back(dotItem);
4698 chainValue->items.push_back(key);
4699 break;
4700 }
4701 default: YUEE("AST node mismatch", key); break;
4702 }
4703 auto assign = assignment->action.to<Assign_t>();
4704 assign->values.clear();
4705 assign->values.push_back(metaNormalPair->value);
4706 transformAssignment(assignment, temp);
4707 break;
4708 }
4709 case id<default_pair_t>(): {
4710 throw std::logic_error(_info.errorMessage("invalid default value"sv, static_cast<default_pair_t*>(item)->defVal));
4711 break;
4712 }
4713 case id<meta_default_pair_t>(): {
4714 throw std::logic_error(_info.errorMessage("invalid default value"sv, static_cast<meta_default_pair_t*>(item)->defVal));
4715 break;
4716 }
4647 default: YUEE("AST node mismatch", item); break; 4717 default: YUEE("AST node mismatch", item); break;
4648 } 4718 }
4649 } 4719 }
@@ -4682,6 +4752,123 @@ private:
4682 } 4752 }
4683 } 4753 }
4684 4754
4755 void transformTable(const node_container& values, str_list& out) {
4756 if (values.empty()) {
4757 out.push_back("{ }"s);
4758 return;
4759 }
4760 auto x = values.front();
4761 str_list temp;
4762 incIndentOffset();
4763 auto metatable = x->new_ptr<simple_table_t>();
4764 ast_sel<false, Exp_t, TableBlock_t> metatableItem;
4765 for (auto item : values) {
4766 bool isMetamethod = false;
4767 switch (item->getId()) {
4768 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); break;
4769 case id<variable_pair_t>(): transform_variable_pair(static_cast<variable_pair_t*>(item), temp); break;
4770 case id<normal_pair_t>(): transform_normal_pair(static_cast<normal_pair_t*>(item), temp, false); break;
4771 case id<TableBlockIndent_t>(): transformTableBlockIndent(static_cast<TableBlockIndent_t*>(item), temp); break;
4772 case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(item), temp); break;
4773 case id<meta_variable_pair_t>(): {
4774 isMetamethod = true;
4775 auto mp = static_cast<meta_variable_pair_t*>(item);
4776 if (metatableItem) {
4777 throw std::logic_error(_info.errorMessage("too many metatable declarations"sv, mp->name));
4778 }
4779 auto name = _parser.toString(mp->name);
4780 _buf << "__"sv << name << ':' << name;
4781 auto newPair = toAst<normal_pair_t>(clearBuf(), item);
4782 metatable->pairs.push_back(newPair);
4783 break;
4784 }
4785 case id<meta_normal_pair_t>(): {
4786 isMetamethod = true;
4787 auto mp = static_cast<meta_normal_pair_t*>(item);
4788 auto newPair = item->new_ptr<normal_pair_t>();
4789 if (mp->key) {
4790 if (metatableItem) {
4791 throw std::logic_error(_info.errorMessage("too many metatable declarations"sv, mp->key));
4792 }
4793 switch (mp->key->getId()) {
4794 case id<Name_t>(): {
4795 auto key = _parser.toString(mp->key);
4796 _buf << "__"sv << key;
4797 auto newKey = toAst<KeyName_t>(clearBuf(), mp->key);
4798 newPair->key.set(newKey);
4799 break;
4800 }
4801 case id<Exp_t>():
4802 newPair->key.set(mp->key);
4803 break;
4804 default: YUEE("AST node mismatch", mp->key); break;
4805 }
4806 newPair->value.set(mp->value);
4807 metatable->pairs.push_back(newPair);
4808 } else {
4809 if (!metatable->pairs.empty()) {
4810 throw std::logic_error(_info.errorMessage("too many metatable declarations"sv, mp->value));
4811 }
4812 metatableItem.set(mp->value);
4813 }
4814 break;
4815 }
4816 case id<default_pair_t>(): {
4817 throw std::logic_error(_info.errorMessage("invalid default value"sv, static_cast<default_pair_t*>(item)->defVal));
4818 break;
4819 }
4820 case id<meta_default_pair_t>(): {
4821 throw std::logic_error(_info.errorMessage("invalid default value"sv, static_cast<meta_default_pair_t*>(item)->defVal));
4822 break;
4823 }
4824 default: YUEE("AST node mismatch", item); break;
4825 }
4826 if (!isMetamethod) {
4827 temp.back() = indent() + (item == values.back() ? temp.back() : temp.back() + ',') + nll(item);
4828 }
4829 }
4830 if (metatable->pairs.empty() && !metatableItem) {
4831 out.push_back('{' + nll(x) + join(temp));
4832 decIndentOffset();
4833 out.back() += (indent() + '}');
4834 } else {
4835 auto tabStr = globalVar("setmetatable"sv, x);
4836 tabStr += '(';
4837 if (temp.empty()) {
4838 decIndentOffset();
4839 tabStr += "{ }"sv;
4840 } else {
4841 tabStr += ('{' + nll(x) + join(temp));
4842 decIndentOffset();
4843 tabStr += (indent() + '}');
4844 }
4845 tabStr += ", "sv;
4846 str_list tmp;
4847 if (!metatable->pairs.empty()) {
4848 transform_simple_table(metatable, tmp);
4849 } else switch (metatableItem->getId()) {
4850 case id<Exp_t>():
4851 transformExp(static_cast<Exp_t*>(metatableItem.get()), tmp, ExpUsage::Closure);
4852 break;
4853 case id<TableBlock_t>():
4854 transformTableBlock(static_cast<TableBlock_t*>(metatableItem.get()), tmp);
4855 break;
4856 }
4857 tabStr += tmp.back();
4858 tabStr += ')';
4859 out.push_back(tabStr);
4860 }
4861 }
4862
4863 void transformTableLit(TableLit_t* table, str_list& out) {
4864 const auto& values = table->values.objects();
4865 if (hasSpreadExp(values)) {
4866 transformSpreadTable(values, out, ExpUsage::Closure);
4867 } else {
4868 transformTable(values, out);
4869 }
4870 }
4871
4685 void transformCompCommon(Comprehension_t* comp, str_list& out) { 4872 void transformCompCommon(Comprehension_t* comp, str_list& out) {
4686 str_list temp; 4873 str_list temp;
4687 auto x = comp; 4874 auto x = comp;
@@ -6079,115 +6266,8 @@ private:
6079 } 6266 }
6080 } 6267 }
6081 6268
6082 void transformTable(ast_node* table, const node_container& pairs, str_list& out) {
6083 if (pairs.empty()) {
6084 out.push_back("{ }"s);
6085 return;
6086 }
6087 str_list temp;
6088 incIndentOffset();
6089 auto metatable = table->new_ptr<simple_table_t>();
6090 ast_sel<false, Exp_t, TableBlock_t> metatableItem;
6091 for (auto pair : pairs) {
6092 bool isMetamethod = false;
6093 switch (pair->getId()) {
6094 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(pair), temp, ExpUsage::Closure); break;
6095 case id<variable_pair_t>(): transform_variable_pair(static_cast<variable_pair_t*>(pair), temp); break;
6096 case id<normal_pair_t>(): transform_normal_pair(static_cast<normal_pair_t*>(pair), temp, false); break;
6097 case id<TableBlockIndent_t>(): transformTableBlockIndent(static_cast<TableBlockIndent_t*>(pair), temp); break;
6098 case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(pair), temp); break;
6099 case id<meta_variable_pair_t>(): {
6100 isMetamethod = true;
6101 auto mp = static_cast<meta_variable_pair_t*>(pair);
6102 if (metatableItem) {
6103 throw std::logic_error(_info.errorMessage("too many metatable declarations"sv, mp->name));
6104 }
6105 auto name = _parser.toString(mp->name);
6106 _buf << "__"sv << name << ':' << name;
6107 auto newPair = toAst<normal_pair_t>(clearBuf(), pair);
6108 metatable->pairs.push_back(newPair);
6109 break;
6110 }
6111 case id<meta_normal_pair_t>(): {
6112 isMetamethod = true;
6113 auto mp = static_cast<meta_normal_pair_t*>(pair);
6114 auto newPair = pair->new_ptr<normal_pair_t>();
6115 if (mp->key) {
6116 if (metatableItem) {
6117 throw std::logic_error(_info.errorMessage("too many metatable declarations"sv, mp->key));
6118 }
6119 switch (mp->key->getId()) {
6120 case id<Name_t>(): {
6121 auto key = _parser.toString(mp->key);
6122 _buf << "__"sv << key;
6123 auto newKey = toAst<KeyName_t>(clearBuf(), mp->key);
6124 newPair->key.set(newKey);
6125 break;
6126 }
6127 case id<Exp_t>():
6128 newPair->key.set(mp->key);
6129 break;
6130 default: YUEE("AST node mismatch", mp->key); break;
6131 }
6132 newPair->value.set(mp->value);
6133 metatable->pairs.push_back(newPair);
6134 } else {
6135 if (!metatable->pairs.empty()) {
6136 throw std::logic_error(_info.errorMessage("too many metatable declarations"sv, mp->value));
6137 }
6138 metatableItem.set(mp->value);
6139 }
6140 break;
6141 }
6142 case id<default_pair_t>(): {
6143 throw std::logic_error(_info.errorMessage("invalid use of default value"sv, static_cast<default_pair_t*>(pair)->defVal));
6144 break;
6145 }
6146 case id<meta_default_pair_t>(): {
6147 throw std::logic_error(_info.errorMessage("invalid use of default value"sv, static_cast<meta_default_pair_t*>(pair)->defVal));
6148 break;
6149 }
6150 default: YUEE("AST node mismatch", pair); break;
6151 }
6152 if (!isMetamethod) {
6153 temp.back() = indent() + (pair == pairs.back() ? temp.back() : temp.back() + ',') + nll(pair);
6154 }
6155 }
6156 if (metatable->pairs.empty() && !metatableItem) {
6157 out.push_back('{' + nll(table) + join(temp));
6158 decIndentOffset();
6159 out.back() += (indent() + '}');
6160 } else {
6161 auto tabStr = globalVar("setmetatable"sv, table);
6162 tabStr += '(';
6163 if (temp.empty()) {
6164 decIndentOffset();
6165 tabStr += "{ }"sv;
6166 } else {
6167 tabStr += ('{' + nll(table) + join(temp));
6168 decIndentOffset();
6169 tabStr += (indent() + '}');
6170 }
6171 tabStr += ", "sv;
6172 str_list tmp;
6173 if (!metatable->pairs.empty()) {
6174 transform_simple_table(metatable, tmp);
6175 } else switch (metatableItem->getId()) {
6176 case id<Exp_t>():
6177 transformExp(static_cast<Exp_t*>(metatableItem.get()), tmp, ExpUsage::Closure);
6178 break;
6179 case id<TableBlock_t>():
6180 transformTableBlock(static_cast<TableBlock_t*>(metatableItem.get()), tmp);
6181 break;
6182 }
6183 tabStr += tmp.back();
6184 tabStr += ')';
6185 out.push_back(tabStr);
6186 }
6187 }
6188
6189 void transform_simple_table(simple_table_t* table, str_list& out) { 6269 void transform_simple_table(simple_table_t* table, str_list& out) {
6190 transformTable(table, table->pairs.objects(), out); 6270 transformTable(table->pairs.objects(), out);
6191 } 6271 }
6192 6272
6193 void transformTblComprehension(TblComprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { 6273 void transformTblComprehension(TblComprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
@@ -6284,11 +6364,16 @@ private:
6284 } 6364 }
6285 6365
6286 void transformTableBlockIndent(TableBlockIndent_t* table, str_list& out) { 6366 void transformTableBlockIndent(TableBlockIndent_t* table, str_list& out) {
6287 transformTable(table, table->values.objects(), out); 6367 transformTable(table->values.objects(), out);
6288 } 6368 }
6289 6369
6290 void transformTableBlock(TableBlock_t* table, str_list& out) { 6370 void transformTableBlock(TableBlock_t* table, str_list& out) {
6291 transformTable(table, table->values.objects(), out); 6371 const auto& values = table->values.objects();
6372 if (hasSpreadExp(values)) {
6373 transformSpreadTable(values, out, ExpUsage::Closure);
6374 } else {
6375 transformTable(values, out);
6376 }
6292 } 6377 }
6293 6378
6294 void transformDo(Do_t* doNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { 6379 void transformDo(Do_t* doNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp
index 0c08d4f..1f1b57c 100755
--- a/src/yuescript/yue_parser.cpp
+++ b/src/yuescript/yue_parser.cpp
@@ -28,9 +28,8 @@ std::unordered_set<std::string> Keywords = {
28 "or", "repeat", "return", "then", "true", 28 "or", "repeat", "return", "then", "true",
29 "until", "while", // Lua keywords 29 "until", "while", // Lua keywords
30 "as", "class", "continue", "export", "extends", 30 "as", "class", "continue", "export", "extends",
31 "from", "global", "import", "is", "macro", 31 "from", "global", "import", "macro", "switch",
32 "switch", "try", "unless", "using", "when", 32 "try", "unless", "using", "when", "with" // Yue keywords
33 "with" // Yue keywords
34}; 33};
35 34
36YueParser::YueParser() { 35YueParser::YueParser() {
@@ -219,7 +218,7 @@ YueParser::YueParser() {
219 218
220 BreakLoop = (expr("break") | expr("continue")) >> not_(AlphaNum); 219 BreakLoop = (expr("break") | expr("continue")) >> not_(AlphaNum);
221 220
222 Return = key("return") >> -ExpListLow; 221 Return = key("return") >> -(TableBlock | ExpListLow);
223 222
224 WithExp = ExpList >> -Assign; 223 WithExp = ExpList >> -Assign;
225 224
@@ -556,7 +555,7 @@ YueParser::YueParser() {
556 555
557 KeyValue = variable_pair | normal_pair | meta_variable_pair | meta_normal_pair; 556 KeyValue = variable_pair | normal_pair | meta_variable_pair | meta_normal_pair;
558 KeyValueList = KeyValue >> *(sym(',') >> KeyValue); 557 KeyValueList = KeyValue >> *(sym(',') >> KeyValue);
559 KeyValueLine = CheckIndent >> (KeyValueList >> -sym(',') | TableBlockIndent | Space >> expr('*') >> (Exp | TableBlock)); 558 KeyValueLine = CheckIndent >> (KeyValueList >> -sym(',') | TableBlockIndent | Space >> expr('*') >> (SpreadExp | Exp | TableBlock));
560 559
561 FnArgDef = (Variable | SelfName >> -existential_op) >> -(sym('=') >> Space >> Exp); 560 FnArgDef = (Variable | SelfName >> -existential_op) >> -(sym('=') >> Space >> Exp);
562 561
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h
index eeadaf6..159bbca 100755
--- a/src/yuescript/yue_parser.h
+++ b/src/yuescript/yue_parser.h
@@ -15,6 +15,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
15#include <list> 15#include <list>
16#include <sstream> 16#include <sstream>
17#include <string_view> 17#include <string_view>
18#include <memory>
18 19
19#include "yuescript/ast.hpp" 20#include "yuescript/ast.hpp"
20#include "yuescript/yue_ast.h" 21#include "yuescript/yue_ast.h"