From 84b93d0e43e7248fd00df6957d55a954c48628d7 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Fri, 22 Apr 2022 18:00:20 +0800 Subject: adding table spreading syntax. --- src/yuescript/yue_ast.h | 7 +- src/yuescript/yue_compiler.cpp | 212 ++++++++++++++++++++++++++++++++++++++--- src/yuescript/yue_parser.cpp | 4 +- src/yuescript/yue_parser.h | 1 + 4 files changed, 209 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index b5ceac1..ed6f7d2 100755 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h @@ -605,10 +605,15 @@ AST_END(default_value) class default_pair_t; class meta_default_pair_t; +AST_NODE(SpreadExp) + ast_ptr exp; + AST_MEMBER(SpreadExp, &exp) +AST_END(SpreadExp) + AST_NODE(TableLit) ast_ptr sep; ast_sel_list values; AST_MEMBER(TableLit, &sep, &values) AST_END(TableLit) diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 17fbaf6..4fb14b6 100755 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -60,7 +60,7 @@ using namespace parserlib; typedef std::list str_list; -const std::string_view version = "0.10.12"sv; +const std::string_view version = "0.10.14"sv; const std::string_view extension = "yue"sv; class YueCompilerImpl { @@ -1353,6 +1353,16 @@ private: out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment)); return; } + case id(): { + auto tableLit = static_cast(value); + if (hasSpreadExp(tableLit)) { + auto expList = assignment->expList.get(); + std::string preDefine = getPredefine(assignment); + transformTableLit(tableLit, out, true, ExpUsage::Assignment, expList); + out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment)); + return; + } + } } auto exp = ast_cast(value); BREAK_IF(!exp); @@ -2665,7 +2675,7 @@ private: case id(): transformTry(static_cast(value), out, ExpUsage::Closure); break; case id(): transform_unary_value(static_cast(value), out); break; case id(): transformTblComprehension(static_cast(value), out, ExpUsage::Closure); break; - case id(): transformTableLit(static_cast(value), out); break; + case id(): transformTableLit(static_cast(value), out, false, ExpUsage::Closure); break; case id(): transformComprehension(static_cast(value), out, ExpUsage::Closure); break; case id(): transformFunLit(static_cast(value), out); break; case id(): transformNum(static_cast(value), out); break; @@ -3274,6 +3284,13 @@ private: case id(): transformIf(static_cast(value), out, ExpUsage::Return); return; + case id(): { + auto tableLit = static_cast(value); + if (hasSpreadExp(tableLit)) { + transformTableLit(tableLit, out, true, ExpUsage::Return); + return; + } + } } } else if (auto chainValue = singleValue->item.as()) { if (specialChainValue(chainValue) != ChainType::Common) { @@ -3834,6 +3851,12 @@ private: void transformChainList(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { auto x = chainList.front(); + if (chainList.size() > 1) { + auto callable = ast_cast(x); + if (callable && callable->item.is()) { + throw std::logic_error(_info.errorMessage("can not access variadic arguments directly"sv, x)); + } + } str_list temp; switch (x->getId()) { case id(): @@ -4429,7 +4452,7 @@ private: case id(): transformSingleString(static_cast(arg), temp); break; case id(): transformDoubleString(static_cast(arg), temp); break; case id(): transformLuaString(static_cast(arg), temp); break; - case id(): transformTableLit(static_cast(arg), temp); break; + case id(): transformTableLit(static_cast(arg), temp, false, ExpUsage::Closure); break; default: YUEE("AST node mismatch", arg); break; } } @@ -4472,8 +4495,160 @@ private: out.push_back(_parser.toString(num)); } - void transformTableLit(TableLit_t* table, str_list& out) { - transformTable(table, table->values.objects(), out); + bool hasSpreadExp(TableLit_t* table) { + for (auto item : table->values.objects()) { + if (ast_is(item)) return true; + } + return false; + } + + void transformTableLit(TableLit_t* table, str_list& out, bool spreading, ExpUsage usage, ExpList_t* assignList = nullptr) { + if (spreading) { + auto x = table; + switch (usage) { + case ExpUsage::Closure: + _enableReturn.push(true); + pushAnonVarArg(); + pushScope(); + break; + case ExpUsage::Assignment: + pushScope(); + break; + default: + break; + } + str_list temp; + std::string tableVar = getUnusedName("_tab_"sv); + forceAddToScope(tableVar); + auto it = table->values.objects().begin(); + if (ast_is(*it)) { + temp.push_back(indent() + "local "s + tableVar + " = { }"s + nll(x)); + } else { + auto initialTab = x->new_ptr(); + while (it != table->values.objects().end() && !ast_is(*it)) { + initialTab->values.push_back(*it); + ++it; + } + transformTableLit(initialTab, temp, false, ExpUsage::Closure); + temp.back() = indent() + "local "s + tableVar + " = "s + temp.back() + nll(*it); + } + for (; it != table->values.objects().end(); ++it) { + auto item = *it; + switch (item->getId()) { + case id(): { + auto spread = static_cast(item); + std::string keyVar = getUnusedName("_key_"sv); + std::string valueVar = getUnusedName("_value_"sv); + auto targetStr = _parser.toString(spread->exp); + _buf << "for "sv << keyVar << ',' << valueVar + << " in pairs! do "sv + << tableVar << '[' << keyVar << "]="sv << valueVar; + auto forEach = toAst(clearBuf(), spread); + auto chainValue = singleValueFrom(forEach->loopValue.to())->item.to(); + ast_to(*(++chainValue->items.objects().begin()))->args.push_back(spread->exp); + transformForEach(forEach, temp); + break; + } + case id(): { + auto variablePair = static_cast(item); + auto nameStr = _parser.toString(variablePair->name); + auto assignment = toAst(tableVar + '.' + nameStr + '=' + nameStr, item); + transformAssignment(assignment, temp); + break; + } + case id(): { + auto normalPair = static_cast(item); + auto assignment = toAst(tableVar + "=nil"s, item); + auto chainValue = singleValueFrom(ast_to(assignment->expList->exprs.front()))->item.to(); + auto key = normalPair->key.get(); + switch (key->getId()) { + case id(): { + auto keyName = static_cast(key); + ast_ptr chainItem; + if (auto name = keyName->name.as()) { + auto dotItem = x->new_ptr(); + dotItem->name.set(name); + chainItem = dotItem.get(); + } else { + auto selfName = keyName->name.to(); + auto callable = x->new_ptr(); + callable->item.set(selfName); + auto chainValue = x->new_ptr(); + chainValue->items.push_back(callable); + auto value = x->new_ptr(); + value->item.set(chainValue); + auto exp = newExp(value, key); + chainItem = exp.get(); + } + chainValue->items.push_back(chainItem); + break; + } + case id(): + chainValue->items.push_back(key); + break; + case id(): + case id(): + case id(): { + auto strNode = x->new_ptr(); + strNode->str.set(key); + chainValue->items.push_back(strNode); + break; + } + default: YUEE("AST node mismatch", key); break; + } + auto assign = assignment->action.to(); + assign->values.clear(); + assign->values.push_back(normalPair->value); + transformAssignment(assignment, temp); + break; + } + case id(): { + auto assignment = toAst(tableVar + "[]=nil"s, item); + auto assign = assignment->action.to(); + assign->values.clear(); + assign->values.push_back(item); + transformAssignment(assignment, temp); + break; + } + default: YUEE("AST node mismatch", item); break; + } + } + switch (usage) { + case ExpUsage::Common: + break; + case ExpUsage::Closure: { + out.push_back(join(temp)); + out.back().append(indent() + "return "s + tableVar + nlr(x)); + popScope(); + out.back().insert(0, anonFuncStart() + nll(x)); + out.back().append(indent() + anonFuncEnd()); + popAnonVarArg(); + _enableReturn.pop(); + break; + } + case ExpUsage::Assignment: { + auto assign = x->new_ptr(); + assign->values.push_back(toAst(tableVar, x)); + auto assignment = x->new_ptr(); + assignment->expList.set(assignList); + assignment->action.set(assign); + transformAssignment(assignment, temp); + popScope(); + out.push_back(join(temp)); + out.back() = indent() + "do"s + nll(x) + + out.back() + indent() + "end"s + nlr(x); + break; + } + case ExpUsage::Return: + out.push_back(join(temp)); + out.back().append(indent() + "return "s + tableVar + nlr(x)); + break; + default: + break; + } + } else { + transformTable(table, table->values.objects(), out); + } } void transformCompCommon(Comprehension_t* comp, str_list& out) { @@ -5070,14 +5245,15 @@ private: out.push_back(name + " = "s + name); } - void transform_normal_pair(normal_pair_t* pair, str_list& out) { + void transform_normal_pair(normal_pair_t* pair, str_list& out, bool assignClass) { auto key = pair->key.get(); str_list temp; switch (key->getId()) { case id(): { - transformKeyName(static_cast(key), temp); - if (LuaKeywords.find(temp.back()) != LuaKeywords.end()) { - temp.back() = "[\""s + temp.back() + "\"]"s; + auto keyName = static_cast(key); + transformKeyName(keyName, temp); + if (keyName->name.is() && !assignClass) { + temp.back() = '[' + temp.back() + ']'; } break; } @@ -5109,8 +5285,18 @@ private: void transformKeyName(KeyName_t* keyName, str_list& out) { auto name = keyName->name.get(); switch (name->getId()) { - case id(): transformSelfName(static_cast(name), out); break; - case id(): out.push_back(_parser.toString(name)); break; + case id(): + transformSelfName(static_cast(name), out); + break; + case id(): { + auto nameStr = _parser.toString(name); + if (LuaKeywords.find(nameStr) != LuaKeywords.end()) { + out.push_back("[\""s + nameStr + "\"]"s); + } else { + out.push_back(nameStr); + } + break; + } default: YUEE("AST node mismatch", name); break; } } @@ -5531,7 +5717,7 @@ private: transform_variable_pair(static_cast(keyValue), temp); break; case id(): - transform_normal_pair(static_cast(keyValue), temp); + transform_normal_pair(static_cast(keyValue), temp, true); break; default: YUEE("AST node mismatch", keyValue); break; } @@ -5876,7 +6062,7 @@ private: switch (pair->getId()) { case id(): transformExp(static_cast(pair), temp, ExpUsage::Closure); break; case id(): transform_variable_pair(static_cast(pair), temp); break; - case id(): transform_normal_pair(static_cast(pair), temp); break; + case id(): transform_normal_pair(static_cast(pair), temp, false); break; case id(): transformTableBlockIndent(static_cast(pair), temp); break; case id(): transformTableBlock(static_cast(pair), temp); break; case id(): { diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index ab9b657..0c08d4f 100755 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -469,7 +469,9 @@ YueParser::YueParser() { and_(expr('[')) >> LuaString | and_(expr('{')) >> TableLit); - TableValue = ((KeyValue | Exp) >> not_(sym('='))) | meta_default_pair | default_pair; + SpreadExp = sym("...") >> Exp; + + TableValue = ((KeyValue | SpreadExp | Exp) >> not_(sym('='))) | meta_default_pair | default_pair; table_lit_lines = SpaceBreak >> TableLitLine >> *(-sym(',') >> SpaceBreak >> TableLitLine) >> -sym(','); diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 6be8451..eeadaf6 100755 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h @@ -281,6 +281,7 @@ private: AST_RULE(Invoke) AST_RULE(existential_op) AST_RULE(table_appending_op) + AST_RULE(SpreadExp) AST_RULE(TableLit) AST_RULE(TableBlock) AST_RULE(TableBlockIndent) -- cgit v1.2.3-55-g6feb