diff options
| author | Li Jin <dragon-fly@qq.com> | 2026-03-26 12:02:35 +0800 |
|---|---|---|
| committer | Li Jin <dragon-fly@qq.com> | 2026-03-26 12:02:35 +0800 |
| commit | df262171918e6ecc241bff6cfcf81b097ec00533 (patch) | |
| tree | 336203cffe33145610b3510601f39d9427e4b16b /src | |
| parent | ad0cd3a39d5d77ec32d2f203c7258f727a06ba6e (diff) | |
| download | yuescript-df262171918e6ecc241bff6cfcf81b097ec00533.tar.gz yuescript-df262171918e6ecc241bff6cfcf81b097ec00533.tar.bz2 yuescript-df262171918e6ecc241bff6cfcf81b097ec00533.zip | |
fix: empty table pattern in switch generates valid Lua code
- Add EmptyTableType enum to distinguish [] and {} patterns
- [] (empty list) generates '#x == 0' check
- {} (empty table) generates 'next(x) == nil' check
- Fixes issue #249
Diffstat (limited to 'src')
| -rw-r--r-- | src/yuescript/yue_compiler.cpp | 43 |
1 files changed, 39 insertions, 4 deletions
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index b9c9330..76d6b0f 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
| @@ -478,11 +478,18 @@ private: | |||
| 478 | ast_ptr<true, Exp_t> defVal; | 478 | ast_ptr<true, Exp_t> defVal; |
| 479 | }; | 479 | }; |
| 480 | 480 | ||
| 481 | enum class EmptyTableType { | ||
| 482 | None, | ||
| 483 | EmptyList, | ||
| 484 | EmptyTable | ||
| 485 | }; | ||
| 486 | |||
| 481 | struct Destructure { | 487 | struct Destructure { |
| 482 | ast_ptr<true, ast_node> value; | 488 | ast_ptr<true, ast_node> value; |
| 483 | std::string valueVar; | 489 | std::string valueVar; |
| 484 | std::list<DestructItem> items; | 490 | std::list<DestructItem> items; |
| 485 | ast_ptr<false, ExpListAssign_t> inlineAssignment; | 491 | ast_ptr<false, ExpListAssign_t> inlineAssignment; |
| 492 | EmptyTableType emptyTableType = EmptyTableType::None; | ||
| 486 | }; | 493 | }; |
| 487 | 494 | ||
| 488 | enum class ExpUsage { | 495 | enum class ExpUsage { |
| @@ -3425,10 +3432,9 @@ private: | |||
| 3425 | break; | 3432 | break; |
| 3426 | default: YUEE("AST node mismatch", destructNode); break; | 3433 | default: YUEE("AST node mismatch", destructNode); break; |
| 3427 | } | 3434 | } |
| 3428 | if (dlist->empty()) { | 3435 | bool emptyTablePattern = dlist->empty(); |
| 3429 | if (!optional) { | 3436 | if (emptyTablePattern && !optional) { |
| 3430 | throw CompileError("expect items to be destructured"sv, destructNode); | 3437 | throw CompileError("expect items to be destructured"sv, destructNode); |
| 3431 | } | ||
| 3432 | } | 3438 | } |
| 3433 | for (auto item : *dlist) { | 3439 | for (auto item : *dlist) { |
| 3434 | switch (item->get_id()) { | 3440 | switch (item->get_id()) { |
| @@ -3554,6 +3560,26 @@ private: | |||
| 3554 | extraScope = true; | 3560 | extraScope = true; |
| 3555 | } | 3561 | } |
| 3556 | } | 3562 | } |
| 3563 | // Handle empty table pattern for switch matching | ||
| 3564 | if (emptyTablePattern) { | ||
| 3565 | Destructure emptyDestruct; | ||
| 3566 | if (!varDefOnly) { | ||
| 3567 | emptyDestruct.value = valueItems.back(); | ||
| 3568 | emptyDestruct.valueVar = singleVariableFrom(emptyDestruct.value, AccessType::None); | ||
| 3569 | } | ||
| 3570 | switch (destructNode->get_id()) { | ||
| 3571 | case id<Comprehension_t>(): | ||
| 3572 | emptyDestruct.emptyTableType = EmptyTableType::EmptyList; | ||
| 3573 | break; | ||
| 3574 | case id<TableLit_t>(): | ||
| 3575 | case id<SimpleTable_t>(): | ||
| 3576 | emptyDestruct.emptyTableType = EmptyTableType::EmptyTable; | ||
| 3577 | break; | ||
| 3578 | default: | ||
| 3579 | break; | ||
| 3580 | } | ||
| 3581 | destructs.push_back(std::move(emptyDestruct)); | ||
| 3582 | } | ||
| 3557 | TableLit_t* tabs[] = {subDestruct.get(), subMetaDestruct.get()}; | 3583 | TableLit_t* tabs[] = {subDestruct.get(), subMetaDestruct.get()}; |
| 3558 | for (auto tab : tabs) { | 3584 | for (auto tab : tabs) { |
| 3559 | if (!tab->values.empty()) { | 3585 | if (!tab->values.empty()) { |
| @@ -12129,6 +12155,15 @@ private: | |||
| 12129 | continue; | 12155 | continue; |
| 12130 | } | 12156 | } |
| 12131 | const auto& destruct = std::get<Destructure>(des); | 12157 | const auto& destruct = std::get<Destructure>(des); |
| 12158 | // Handle empty table pattern | ||
| 12159 | if (destruct.emptyTableType != EmptyTableType::None) { | ||
| 12160 | if (destruct.emptyTableType == EmptyTableType::EmptyList) { | ||
| 12161 | conds.push_back('#' + objVar + " == 0"); | ||
| 12162 | } else { | ||
| 12163 | conds.push_back(globalVar("next"sv, branch, AccessType::Read) + '(' + objVar + ") == nil"); | ||
| 12164 | } | ||
| 12165 | continue; | ||
| 12166 | } | ||
| 12132 | for (const auto& item : destruct.items) { | 12167 | for (const auto& item : destruct.items) { |
| 12133 | if (!item.defVal) { | 12168 | if (!item.defVal) { |
| 12134 | if (!isAssignable(item.target)) { | 12169 | if (!isAssignable(item.target)) { |
