diff options
-rwxr-xr-x | doc/docs/doc/README.md | 68 | ||||
-rw-r--r-- | spec/inputs/return.yue | 13 | ||||
-rw-r--r-- | spec/inputs/tables.yue | 23 | ||||
-rw-r--r-- | spec/outputs/return.lua | 24 | ||||
-rw-r--r-- | spec/outputs/tables.lua | 61 | ||||
-rwxr-xr-x | src/yuescript/yue_ast.h | 6 | ||||
-rwxr-xr-x | src/yuescript/yue_compiler.cpp | 351 | ||||
-rwxr-xr-x | src/yuescript/yue_parser.cpp | 9 | ||||
-rwxr-xr-x | src/yuescript/yue_parser.h | 1 |
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** |
122 | Require "your_yuescript_entry.yue" in Lua. | 122 | Require "your_yuescript_entry.yue" in Lua. |
123 | ```Lua | 123 | ```Lua |
124 | require("yue")("your_yuescript_entry") | 124 | require("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** |
129 | Require Yuescript module and rewite message by hand. | 129 | Require Yuescript module and rewite message by hand. |
130 | ```lua | 130 | ```lua |
131 | local yue = require("yue") | 131 | local yue = require("yue") |
@@ -136,7 +136,7 @@ end, function(err) | |||
136 | end) | 136 | end) |
137 | ``` | 137 | ``` |
138 | 138 | ||
139 | * **Case 3** | 139 | * **Case 3** |
140 | Use the Yuescript compiler function in Lua. | 140 | Use the Yuescript compiler function in Lua. |
141 | ```lua | 141 | ```lua |
142 | local yue = require("yue") | 142 | local 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 | |||
611 | You can concatenate array tables or hash tables using spread operator `...` before expressions in table literals. | ||
612 | |||
613 | ```moonscript | ||
614 | parts = | ||
615 | * "shoulders" | ||
616 | * "knees" | ||
617 | lyrics = | ||
618 | * "head" | ||
619 | * ...parts | ||
620 | * "and" | ||
621 | * "toes" | ||
622 | |||
623 | copy = {...other} | ||
624 | |||
625 | a = {1, 2, 3, x: 1} | ||
626 | b = {4, 5, y: 1} | ||
627 | merge = {...a, ...b} | ||
628 | ``` | ||
629 | <YueDisplay> | ||
630 | <pre> | ||
631 | parts = | ||
632 | * "shoulders" | ||
633 | * "knees" | ||
634 | lyrics = | ||
635 | * "head" | ||
636 | * ...parts | ||
637 | * "and" | ||
638 | * "toes" | ||
639 | |||
640 | copy = {...other} | ||
641 | |||
642 | a = {1, 2, 3, x: 1} | ||
643 | a = {4, 5, y: 1} | ||
644 | merge = {...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 | ||
1023 | You 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 | ||
986 | Destructuring can also show up in places where an assignment implicitly takes place. An example of this is a for loop: | 1036 | Destructuring 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 | ||
52 | do | ||
53 | return | ||
54 | :value | ||
55 | itemA: 123 | ||
56 | itemB: "abc" | ||
57 | |||
58 | do | ||
59 | return | ||
60 | * 1 | ||
61 | * 2 | ||
62 | * ...three | ||
63 | * 4 | ||
64 | |||
52 | _ = -> a\b | 65 | _ = -> a\b |
53 | do a\b | 66 | do 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 | ||
284 | parts = | ||
285 | * "shoulders" | ||
286 | * "knees" | ||
287 | |||
288 | lyrics = | ||
289 | * "head" | ||
290 | * ...parts | ||
291 | * "and" | ||
292 | * "toes" | ||
293 | |||
294 | tbBlock = | ||
295 | sub: | ||
296 | :value | ||
297 | * ...items | ||
298 | * ... | ||
299 | |||
300 | func | ||
301 | * ...items | ||
302 | :value | ||
303 | * ... | ||
304 | k: v | ||
305 | * ... | ||
306 | |||
284 | nil | 307 | nil |
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 |
88 | end | 88 | end |
89 | do | ||
90 | return { | ||
91 | value = value, | ||
92 | itemA = 123, | ||
93 | itemB = "abc" | ||
94 | } | ||
95 | end | ||
96 | do | ||
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 | ||
112 | end | ||
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 |
529 | end | 529 | end |
530 | local parts = { | ||
531 | "shoulders", | ||
532 | "knees" | ||
533 | } | ||
534 | local lyrics | ||
535 | do | ||
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 | ||
551 | end | ||
552 | local 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 | } | ||
572 | func((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 | ||
590 | end)(...)) | ||
530 | return nil | 591 | return 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) |
222 | AST_END(ExpList) | 222 | AST_END(ExpList) |
223 | 223 | ||
224 | class TableBlock_t; | ||
225 | |||
224 | AST_NODE(Return) | 226 | AST_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) |
228 | AST_END(Return) | 230 | AST_END(Return) |
229 | 231 | ||
@@ -628,7 +630,7 @@ AST_END(TableBlockIndent) | |||
628 | 630 | ||
629 | AST_NODE(TableBlock) | 631 | AST_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) |
634 | AST_END(TableBlock) | 636 | AST_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 | ||
61 | typedef std::list<std::string> str_list; | 61 | typedef std::list<std::string> str_list; |
62 | 62 | ||
63 | const std::string_view version = "0.10.14"sv; | 63 | const std::string_view version = "0.10.15"sv; |
64 | const std::string_view extension = "yue"sv; | 64 | const std::string_view extension = "yue"sv; |
65 | 65 | ||
66 | class YueCompilerImpl { | 66 | class 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 | ||
36 | YueParser::YueParser() { | 35 | YueParser::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" |