From 249e1de1d32dda2b60b9116c5a4e538475de0192 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Sun, 24 Apr 2022 15:35:53 +0800 Subject: add support for the Fill Operator. fix issue #39. --- spec/inputs/tables.yue | 19 +++ spec/outputs/tables.lua | 127 ++++++++++++---- src/yuescript/yue_compiler.cpp | 326 +++++++++++++++++++++-------------------- 3 files changed, 289 insertions(+), 183 deletions(-) diff --git a/spec/inputs/tables.yue b/spec/inputs/tables.yue index 649c1dc..3a245a7 100644 --- a/spec/inputs/tables.yue +++ b/spec/inputs/tables.yue @@ -262,5 +262,24 @@ tbMixB = { 1, 2, 3 } +const template = { + foo: "Hello" + bar: "World" + baz: "!" +} + +const specialized = { + ...template + bar: "Bob" +} + +specializedB = { + function: -> + ...template + end: -> + if: true + else: false +} + nil diff --git a/spec/outputs/tables.lua b/spec/outputs/tables.lua index b820122..165706d 100644 --- a/spec/outputs/tables.lua +++ b/spec/outputs/tables.lua @@ -351,10 +351,14 @@ local menus = { local tb do local _tab_0 = { } - local _list_0 = other - for _index_0 = 1, #_list_0 do - local _value_0 = _list_0[_index_0] - _tab_0[#_tab_0 + 1] = _value_0 + local _idx_0 = 1 + for _key_0, _value_0 in pairs(other) do + if _idx_0 == _key_0 then + _tab_0[#_tab_0 + 1] = _value_0 + _idx_0 = _idx_0 + 1 + else + _tab_0[_key_0] = _value_0 + end end tb = _tab_0 end @@ -372,9 +376,14 @@ do _with_0:func() _obj_0 = _with_0 end - for _index_0 = 1, #_obj_0 do - local _value_0 = _obj_0[_index_0] - _tab_0[#_tab_0 + 1] = _value_0 + local _idx_0 = 1 + for _key_0, _value_0 in pairs(_obj_0) do + if _idx_0 == _key_0 then + _tab_0[#_tab_0 + 1] = _value_0 + _idx_0 = _idx_0 + 1 + else + _tab_0[_key_0] = _value_0 + end end _tab_0[#_tab_0 + 1] = "a" _tab_0[#_tab_0 + 1] = "b" @@ -386,9 +395,14 @@ do _obj_1 = _obj_2() end end - for _index_0 = 1, #_obj_1 do - local _value_0 = _obj_1[_index_0] - _tab_0[#_tab_0 + 1] = _value_0 + local _idx_1 = 1 + for _key_0, _value_0 in pairs(_obj_1) do + if _idx_1 == _key_0 then + _tab_0[#_tab_0 + 1] = _value_0 + _idx_1 = _idx_1 + 1 + else + _tab_0[_key_0] = _value_0 + end end _tab_0.key = "value" for _index_0 = 1, select('#', ...) do @@ -409,9 +423,14 @@ do end _obj_0 = _accum_0 end - for _index_0 = 1, #_obj_0 do - local _value_0 = _obj_0[_index_0] - _tab_0[#_tab_0 + 1] = _value_0 + local _idx_0 = 1 + for _key_0, _value_0 in pairs(_obj_0) do + if _idx_0 == _key_0 then + _tab_0[#_tab_0 + 1] = _value_0 + _idx_0 = _idx_0 + 1 + else + _tab_0[_key_0] = _value_0 + end end _tab_0[#_tab_0 + 1] = 11 tbMixA = _tab_0 @@ -420,34 +439,92 @@ local tbMixB do local _tab_0 = { } local _obj_0 = ... - for _index_0 = 1, #_obj_0 do - local _value_0 = _obj_0[_index_0] - _tab_0[#_tab_0 + 1] = _value_0 + local _idx_0 = 1 + for _key_0, _value_0 in pairs(_obj_0) do + if _idx_0 == _key_0 then + _tab_0[#_tab_0 + 1] = _value_0 + _idx_0 = _idx_0 + 1 + else + _tab_0[_key_0] = _value_0 + end end local _obj_1 = { ... } - for _index_0 = 1, #_obj_1 do - local _value_0 = _obj_1[_index_0] - _tab_0[#_tab_0 + 1] = _value_0 + local _idx_1 = 1 + for _key_0, _value_0 in pairs(_obj_1) do + if _idx_1 == _key_0 then + _tab_0[#_tab_0 + 1] = _value_0 + _idx_1 = _idx_1 + 1 + else + _tab_0[_key_0] = _value_0 + end end local _obj_2 do local _tab_1 = { } local _obj_3 = ... - for _index_0 = 1, #_obj_3 do - local _value_0 = _obj_3[_index_0] - _tab_1[#_tab_1 + 1] = _value_0 + local _idx_2 = 1 + for _key_0, _value_0 in pairs(_obj_3) do + if _idx_2 == _key_0 then + _tab_1[#_tab_1 + 1] = _value_0 + _idx_2 = _idx_2 + 1 + else + _tab_1[_key_0] = _value_0 + end end _obj_2 = _tab_1 end - for _index_0 = 1, #_obj_2 do - local _value_0 = _obj_2[_index_0] - _tab_0[#_tab_0 + 1] = _value_0 + local _idx_2 = 1 + for _key_0, _value_0 in pairs(_obj_2) do + if _idx_2 == _key_0 then + _tab_0[#_tab_0 + 1] = _value_0 + _idx_2 = _idx_2 + 1 + else + _tab_0[_key_0] = _value_0 + end end _tab_0[#_tab_0 + 1] = 1 _tab_0[#_tab_0 + 1] = 2 _tab_0[#_tab_0 + 1] = 3 tbMixB = _tab_0 end +local template = { + foo = "Hello", + bar = "World", + baz = "!" +} +local specialized = (function() + local _tab_0 = { } + local _idx_0 = 1 + for _key_0, _value_0 in pairs(template) do + if _idx_0 == _key_0 then + _tab_0[#_tab_0 + 1] = _value_0 + _idx_0 = _idx_0 + 1 + else + _tab_0[_key_0] = _value_0 + end + end + _tab_0.bar = "Bob" + return _tab_0 +end)() +local specializedB +do + local _tab_0 = { + ["function"] = function() end + } + local _idx_0 = 1 + for _key_0, _value_0 in pairs(template) do + if _idx_0 == _key_0 then + _tab_0[#_tab_0 + 1] = _value_0 + _idx_0 = _idx_0 + 1 + else + _tab_0[_key_0] = _value_0 + end + end + _tab_0["end"] = function() end + _tab_0["if"] = true + _tab_0["else"] = false + specializedB = _tab_0 +end return nil diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 4dacf42..6a0fba6 100755 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -1358,7 +1358,7 @@ private: if (hasSpreadExp(tableLit)) { auto expList = assignment->expList.get(); std::string preDefine = getPredefine(assignment); - transformTableLit(tableLit, out, true, ExpUsage::Assignment, expList); + transformSpreadTableLit(tableLit, out, ExpUsage::Assignment, expList); out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment)); return; } @@ -2675,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, false, ExpUsage::Closure); break; + case id(): transformTableLit(static_cast(value), out); 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; @@ -3287,7 +3287,7 @@ private: case id(): { auto tableLit = static_cast(value); if (hasSpreadExp(tableLit)) { - transformTableLit(tableLit, out, true, ExpUsage::Return); + transformSpreadTableLit(tableLit, out, ExpUsage::Return); return; } } @@ -4452,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, false, ExpUsage::Closure); break; + case id(): transformTableLit(static_cast(arg), temp); break; default: YUEE("AST node mismatch", arg); break; } } @@ -4502,173 +4502,183 @@ private: 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; + void transformTableLit(TableLit_t* table, str_list& out) { + if (hasSpreadExp(table)) { + transformSpreadTableLit(table, out, ExpUsage::Closure); + } else { + transformTable(table, table->values.objects(), out); + } + } + + void transformSpreadTableLit(TableLit_t* table, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { + 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; } - 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 valueVar = getUnusedName("_value_"sv); - auto objVar = singleVariableFrom(spread->exp); - if (objVar.empty()) { - objVar = getUnusedName("_obj_"); - auto assignment = toAst(objVar + "=nil"s, spread); - auto assign = assignment->action.to(); - assign->values.clear(); - assign->values.push_back(spread->exp); - transformAssignment(assignment, temp); - } - _buf << "for "sv << valueVar - << " in *"sv << objVar << " do "sv - << tableVar << "[]="sv << valueVar; - auto forEach = toAst(clearBuf(), spread); - 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; - } + transformTable(table, initialTab->values.objects(), temp); + 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 indexVar = getUnusedName("_idx_"sv); + std::string keyVar = getUnusedName("_key_"sv); + std::string valueVar = getUnusedName("_value_"sv); + auto objVar = singleVariableFrom(spread->exp); + if (objVar.empty()) { + objVar = getUnusedName("_obj_"); + auto assignment = toAst(objVar + "=nil"s, item); auto assign = assignment->action.to(); assign->values.clear(); - assign->values.push_back(normalPair->value); + assign->values.push_back(spread->exp); transformAssignment(assignment, temp); - break; - } - case id(): { - bool lastVarArg = false; - BLOCK_START - BREAK_IF(item != table->values.back()); - auto value = singleValueFrom(item); - BREAK_IF(!value); - auto chainValue = value->item.as(); - BREAK_IF(!chainValue); - BREAK_IF(chainValue->items.size() != 1); - BREAK_IF((!chainValue->getByPath())); - auto indexVar = getUnusedName("_index_"); - _buf << "for "sv << indexVar << "=1,select '#',...\n\t"sv << tableVar << "[]= select "sv << indexVar << ",..."sv; - transformFor(toAst(clearBuf(), item), temp); - lastVarArg = true; - BLOCK_END - if (!lastVarArg) { - 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(); + forceAddToScope(indexVar); + temp.push_back(indent() + "local "s + indexVar + " = 1"s + nll(item)); + _buf << "for "sv << keyVar << ',' << valueVar << " in pairs "sv << objVar + << "\n\tif "sv << indexVar << "=="sv << keyVar + << "\n\t\t"sv << tableVar << "[]="sv << valueVar + << "\n\t\t"sv << indexVar << "+=1"sv + << "\n\telse "sv << tableVar << '[' << keyVar << "]="sv << valueVar; + auto forEach = toAst(clearBuf(), item); + transformForEach(forEach, temp); 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); + case id(): { + auto variablePair = static_cast(item); + auto nameStr = _parser.toString(variablePair->name); + auto assignment = toAst(tableVar + '.' + nameStr + '=' + nameStr, item); 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)); + 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; - default: + } + case id(): { + bool lastVarArg = false; + BLOCK_START + BREAK_IF(item != table->values.back()); + auto value = singleValueFrom(item); + BREAK_IF(!value); + auto chainValue = value->item.as(); + BREAK_IF(!chainValue); + BREAK_IF(chainValue->items.size() != 1); + BREAK_IF((!chainValue->getByPath())); + auto indexVar = getUnusedName("_index_"); + _buf << "for "sv << indexVar << "=1,select '#',...\n\t"sv << tableVar << "[]= select "sv << indexVar << ",..."sv; + transformFor(toAst(clearBuf(), item), temp); + lastVarArg = true; + BLOCK_END + if (!lastVarArg) { + 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; } - } else { - transformTable(table, table->values.objects(), out); + } + 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; } } -- cgit v1.2.3-55-g6feb