From 792e942f5269655ee03c48400999f3604b84396c Mon Sep 17 00:00:00 2001 From: Li Jin Date: Tue, 17 Aug 2021 16:21:39 +0800 Subject: fix issue #64. --- src/yuescript/yue_ast.h | 30 ++++- src/yuescript/yue_compiler.cpp | 278 +++++++++++++++++++++++++++++++++++++---- src/yuescript/yue_parser.cpp | 9 +- src/yuescript/yue_parser.h | 3 + 4 files changed, 290 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 7d79341..69c9607 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h @@ -426,6 +426,14 @@ AST_NODE(normal_pair) AST_MEMBER(normal_pair, &key, &value) AST_END(normal_pair) +AST_NODE(default_pair) + ast_sel key; + ast_ptr sep; + ast_ptr value; + ast_ptr defVal; + AST_MEMBER(default_pair, &key, &sep, &value, &defVal) +AST_END(default_pair) + AST_NODE(meta_variable_pair) ast_ptr name; AST_MEMBER(meta_variable_pair, &name) @@ -437,6 +445,14 @@ AST_NODE(meta_normal_pair) AST_MEMBER(meta_normal_pair, &key, &value) AST_END(meta_normal_pair) +AST_NODE(meta_default_pair) + ast_sel key; + ast_ptr sep; + ast_ptr value; + ast_ptr defVal; + AST_MEMBER(meta_default_pair, &key, &sep, &value, &defVal) +AST_END(meta_default_pair) + AST_NODE(simple_table) ast_ptr sep; ast_sel_list pairs; @@ -562,21 +578,29 @@ AST_END(Value) AST_LEAF(default_value) AST_END(default_value) +class default_pair_t; +class meta_default_pair_t; + AST_NODE(TableLit) ast_ptr sep; - ast_sel_list values; + ast_sel_list values; AST_MEMBER(TableLit, &sep, &values) AST_END(TableLit) AST_NODE(TableBlockIndent) ast_ptr sep; - ast_sel_list values; + ast_sel_list values; AST_MEMBER(TableBlockIndent, &sep, &values) AST_END(TableBlockIndent) AST_NODE(TableBlock) ast_ptr sep; - ast_sel_list values; + ast_sel_list values; AST_MEMBER(TableBlock, &sep, &values) AST_END(TableBlock) diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index ca846a5..8e4072f 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -56,7 +56,7 @@ using namespace parserlib; typedef std::list str_list; -const std::string_view version = "0.7.17"sv; +const std::string_view version = "0.7.18"sv; const std::string_view extension = "yue"sv; class YueCompilerImpl { @@ -248,6 +248,8 @@ private: bool isVariable = false; std::string name; std::string structure; + ast_ptr defVal; + bool isMetatable = false; }; struct Destructure { @@ -1364,45 +1366,102 @@ private: if (info.second) { transformAssignmentCommon(info.second, temp); } - for (const auto& destruct : info.first) { + for (auto& destruct : info.first) { + std::list> leftPairs; if (destruct.items.size() == 1) { auto& pair = destruct.items.front(); - _buf << indent(); - if (pair.isVariable) { - checkConst(pair.name, assignment); - if (!isDefined(pair.name)) _buf << "local "s; + if (!pair.isVariable && pair.defVal) { + auto objVar = getUnusedName("_obj_"sv); + leftPairs.push_back({pair.name, objVar}); + pair.name = objVar; + pair.isVariable = true; + } + if (pair.isMetatable) { + if (pair.isVariable) { + checkConst(pair.name, assignment); + if (addToScope(pair.name)) { + _buf << indent() << "local "sv << pair.name << nll(assignment); + } + } + bool valueDefined = isDefined(destruct.value); + std::string objVar; + if (valueDefined) { + objVar = destruct.value; + } else { + _buf << indent() << "do"sv << nll(assignment); + pushScope(); + objVar = getUnusedName("_obj_"sv); + addToScope(objVar); + _buf << indent() << "local "sv << objVar << " = "sv << destruct.value << nll(assignment); + temp.push_back(clearBuf()); + } + auto valueExp = toAst(objVar + pair.structure, assignment); + transformExp(valueExp, temp, ExpUsage::Closure); + _buf << indent() << pair.name << " = "sv << temp.back() << nll(assignment); + if (!valueDefined) { + popScope(); + _buf << indent() << "end"sv << nlr(assignment); + } + temp.back() = clearBuf(); + } else { + _buf << indent(); + if (pair.isVariable) { + checkConst(pair.name, assignment); + if (addToScope(pair.name)) _buf << "local "sv; + } + _buf << pair.name << " = "sv << destruct.value << pair.structure << nll(assignment); + temp.push_back(clearBuf()); } - _buf << pair.name << " = "sv << destruct.value << pair.structure << nll(assignment); - addToScope(pair.name); - temp.push_back(clearBuf()); } else if (_parser.match(destruct.value) && isDefined(destruct.value)) { str_list defs, names, values; - for (const auto& item : destruct.items) { + bool isMetatable = false; + for (auto& item : destruct.items) { if (item.isVariable) { checkConst(item.name, assignment); if (addToScope(item.name)) defs.push_back(item.name); + } else if (item.defVal) { + auto objVar = getUnusedName("_obj_"sv); + addToScope(objVar); + defs.push_back(objVar); + leftPairs.push_back({item.name, objVar}); + item.name = objVar; } + if (item.isMetatable) isMetatable = true; names.push_back(item.name); values.push_back(item.structure); } for (auto& v : values) v.insert(0, destruct.value); + if (isMetatable) { + auto newExpList = toAst(join(values, ","sv), assignment); + transformExpList(newExpList, temp); + } else { + temp.push_back(join(values, ", "sv)); + } if (defs.empty()) { - _buf << indent() << join(names, ", "sv) << " = "sv << join(values, ", "sv) << nll(assignment); + _buf << indent() << join(names, ", "sv) << " = "sv << temp.back() << nll(assignment); } else { _buf << indent() << "local "sv; if (defs.size() != names.size()) { - _buf << join(defs,", "sv) << nll(assignment) << indent(); + _buf << join(defs, ", "sv) << nll(assignment) << indent(); } - _buf << join(names, ", "sv) << " = "sv << join(values, ", "sv) << nll(assignment); + _buf << join(names, ", "sv) << " = "sv << temp.back() << nll(assignment); } - temp.push_back(clearBuf()); + temp.back() = clearBuf(); } else { str_list defs, names, values; - for (const auto& item : destruct.items) { + bool isMetatable = false; + for (auto& item : destruct.items) { if (item.isVariable) { checkConst(item.name, assignment); if (addToScope(item.name)) defs.push_back(item.name); + } else if (item.defVal) { + auto objVar = getUnusedName("_obj_"sv); + addToScope(objVar); + defs.push_back(objVar); + leftPairs.push_back({item.name, objVar}); + item.name = objVar; } + if (item.isMetatable) isMetatable = true; names.push_back(item.name); values.push_back(item.structure); } @@ -1410,13 +1469,34 @@ private: _buf << indent() << "do"sv << nll(assignment); pushScope(); auto objVar = getUnusedName("_obj_"sv); + addToScope(objVar); for (auto& v : values) v.insert(0, objVar); + if (isMetatable) { + auto newExpList = toAst(join(values, ","sv), assignment); + transformExpList(newExpList, temp); + } else { + temp.push_back(join(values, ", "sv)); + } _buf << indent() << "local "sv << objVar << " = "sv << destruct.value << nll(assignment); - _buf << indent() << join(names, ", "sv) << " = "sv << join(values, ", "sv) << nll(assignment); + _buf << indent() << join(names, ", "sv) << " = "sv << temp.back() << nll(assignment); popScope(); _buf << indent() << "end"sv << nll(assignment); - temp.push_back(clearBuf()); + temp.back() = clearBuf(); + } + for (const auto& item : destruct.items) { + if (item.defVal) { + auto stmt = toAst(item.name + "=nil if "s + item.name + "==nil", item.defVal); + auto defAssign = stmt->content.as(); + auto assign = defAssign->action.as(); + assign->values.clear(); + assign->values.push_back(item.defVal); + transformStatement(stmt, temp); + } } + for (const auto& item : leftPairs) { + _buf << indent() << item.first << " = "sv << item.second << nll(assignment); + } + temp.push_back(clearBuf()); } out.push_back(join(temp)); } @@ -1463,6 +1543,7 @@ private: if (!tableItems) throw std::logic_error(_info.errorMessage("invalid destructure value"sv, node)); std::list pairs; int index = 0; + auto subMetaDestruct = node->new_ptr(); for (auto pair : *tableItems) { switch (pair->getId()) { case id(): { @@ -1477,7 +1558,8 @@ private: auto subPairs = destructFromExp(pair); for (auto& p : subPairs) { pairs.push_back({p.isVariable, p.name, - '[' + std::to_string(index) + ']' + p.structure}); + '[' + std::to_string(index) + ']' + p.structure, + p.defVal, p.isMetatable}); } } else { bool lintGlobal = _config.lintGlobalVariable; @@ -1494,7 +1576,8 @@ private: pairs.push_back({ isVariable, varName, - '[' + std::to_string(index) + ']' + '[' + std::to_string(index) + ']', + nullptr }); } break; @@ -1503,9 +1586,9 @@ private: auto vp = static_cast(pair); auto name = _parser.toString(vp->name); if (Keywords.find(name) != Keywords.end()) { - pairs.push_back({true, name, "[\""s + name + "\"]"s}); + pairs.push_back({true, name, "[\""s + name + "\"]"s, nullptr}); } else { - pairs.push_back({true, name, '.' + name}); + pairs.push_back({true, name, '.' + name, nullptr}); } break; } @@ -1532,7 +1615,9 @@ private: pairs.push_back({ p.isVariable, p.name, - keyName + p.structure + keyName + p.structure, + p.defVal, + p.isMetatable }); } } else { @@ -1549,7 +1634,8 @@ private: pairs.push_back({ isVariable, varName, - keyName + keyName, + nullptr }); } break; @@ -1560,7 +1646,9 @@ private: pairs.push_back({ p.isVariable, p.name, - keyName + p.structure + keyName + p.structure, + p.defVal, + p.isMetatable }); } } @@ -1574,14 +1662,126 @@ private: pairs.push_back({ p.isVariable, p.name, - '[' + std::to_string(index) + ']' + p.structure + '[' + std::to_string(index) + ']' + p.structure, + p.defVal, + p.isMetatable + }); + } + break; + } + case id() : { + auto dp = static_cast(pair); + std::string keyName, valueStr; + if (dp->key) { + auto key = dp->key->getByPath(); + if (!key) throw std::logic_error(_info.errorMessage("invalid key for destructure"sv, dp)); + keyName = _parser.toString(key); + if (!dp->value) valueStr = keyName; + if (Keywords.find(keyName) != Keywords.end()) { + keyName = "[\""s + keyName + "\"]"s; + } + else { + keyName = "."s + keyName; + } + } + if (auto exp = dp->value.as()) { + if (!isAssignable(exp)) throw std::logic_error(_info.errorMessage("can't destructure value"sv, exp)); + bool lintGlobal = _config.lintGlobalVariable; + _config.lintGlobalVariable = false; + auto varName = singleVariableFrom(exp); + bool isVariable = !varName.empty(); + if (!isVariable) { + str_list temp; + transformExp(exp, temp, ExpUsage::Closure); + varName = std::move(temp.back()); + } + _config.lintGlobalVariable = lintGlobal; + pairs.push_back({ + isVariable, + varName, + keyName, + dp->defVal + }); + } else { + pairs.push_back({ + true, + valueStr, + keyName, + dp->defVal }); } break; } + case id(): { + auto mp = static_cast(pair); + auto newPair = pair->new_ptr(); + if (mp->key) { + auto key = _parser.toString(mp->key); + _buf << "__"sv << key; + auto newKey = toAst(clearBuf(), mp->key); + newPair->key.set(newKey); + if (newPair->value) { + newPair->value.set(mp->value); + } + else { + newPair->value.set(toAst(key, mp->key)); + } + } else { + newPair->value.set(mp->value); + } + newPair->defVal.set(mp->defVal); + subMetaDestruct->values.push_back(newPair); + break; + } + case id(): { + auto mp = static_cast(pair); + auto name = _parser.toString(mp->name); + _buf << "__"sv << name << ':' << name; + auto newPair = toAst(clearBuf(), pair); + subMetaDestruct->values.push_back(newPair); + break; + } + case id(): { + auto mp = static_cast(pair); + auto newPair = pair->new_ptr(); + if (mp->key) { + switch (mp->key->getId()) { + case id(): { + auto key = _parser.toString(mp->key); + _buf << "__"sv << key; + auto newKey = toAst(clearBuf(), mp->key); + newPair->key.set(newKey); + break; + } + case id(): + newPair->key.set(mp->key); + break; + default: YUEE("AST node mismatch", mp->key); break; + } + } + newPair->value.set(mp->value); + subMetaDestruct->values.push_back(newPair); + break; + } default: YUEE("AST node mismatch", pair); break; } } + if (!subMetaDestruct->values.empty()) { + auto simpleValue = subMetaDestruct->new_ptr(); + simpleValue->value.set(subMetaDestruct); + auto value = subMetaDestruct->new_ptr(); + value->item.set(simpleValue); + auto subPairs = destructFromExp(newExp(value, subMetaDestruct)); + for (const auto& p : subPairs) { + pairs.push_back({ + p.isVariable, + p.name, + ".#"s + p.structure, + p.defVal, + true + }); + } + } return pairs; } @@ -1638,6 +1838,26 @@ private: } for (auto item : *dlist) { switch (item->getId()) { + case id(): { + auto mp = static_cast(item); + auto newPair = item->new_ptr(); + if (mp->key) { + auto key = _parser.toString(mp->key); + _buf << "__"sv << key; + auto newKey = toAst(clearBuf(), mp->key); + newPair->key.set(newKey); + if (newPair->value) { + newPair->value.set(mp->value); + } else { + newPair->value.set(toAst(key, mp->key)); + } + } else { + newPair->value.set(mp->value); + } + newPair->defVal.set(mp->defVal); + subMetaDestruct->values.push_back(newPair); + break; + } case id(): { auto mp = static_cast(item); auto name = _parser.toString(mp->name); @@ -5344,6 +5564,14 @@ private: } break; } + case id(): { + throw std::logic_error(_info.errorMessage("invalid use of default value"sv, static_cast(pair)->defVal)); + break; + } + case id(): { + throw std::logic_error(_info.errorMessage("invalid use of default value"sv, static_cast(pair)->defVal)); + break; + } default: YUEE("AST node mismatch", pair); break; } if (!isMetamethod) { diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index f530776..a3e70c6 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -465,7 +465,7 @@ YueParser::YueParser() { and_(expr('[')) >> LuaString | and_(expr('{')) >> TableLit); - TableValue = KeyValue | Exp; + TableValue = KeyValueDef | Exp; table_lit_lines = SpaceBreak >> TableLitLine >> *(-sym(',') >> SpaceBreak >> TableLitLine) >> -sym(','); @@ -536,14 +536,19 @@ YueParser::YueParser() { Space >> LuaString ) >> symx(':') >> not_(':') >> - (Exp | TableBlock | +(SpaceBreak) >> Exp); + (Exp | TableBlock | +SpaceBreak >> Exp); + + default_pair = (sym(':') >> Variable >> not_('#') >> Seperator | KeyName >> symx(':') >> Seperator >> Exp) >> sym('=') >> Exp; meta_variable_pair = sym(':') >> Variable >> expr('#'); meta_normal_pair = Space >> -(Name | symx('[') >> Exp >> sym(']')) >> expr("#:") >> (Exp | TableBlock | +(SpaceBreak) >> Exp); + meta_default_pair = (sym(':') >> Variable >> expr('#') >> Seperator | -Name >> expr("#:") >> Seperator >> Exp) >> sym('=') >> Exp; + KeyValue = variable_pair | normal_pair | meta_variable_pair | meta_normal_pair; + KeyValueDef = (variable_pair | normal_pair | meta_variable_pair | meta_normal_pair) >> not_(sym('=')) | default_pair | meta_default_pair; KeyValueList = KeyValue >> *(sym(',') >> KeyValue); KeyValueLine = CheckIndent >> (KeyValueList >> -sym(',') | TableBlockIndent | Space >> expr('*') >> (Exp | TableBlock)); diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 2a3c1e4..71519f3 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h @@ -148,6 +148,7 @@ private: rule CompClause; rule Chain; rule KeyValue; + rule KeyValueDef; rule single_string_inner; rule interp; rule double_string_plain; @@ -289,8 +290,10 @@ private: AST_RULE(Export) AST_RULE(variable_pair) AST_RULE(normal_pair) + AST_RULE(default_pair) AST_RULE(meta_variable_pair) AST_RULE(meta_normal_pair) + AST_RULE(meta_default_pair) AST_RULE(FnArgDef) AST_RULE(FnArgDefList) AST_RULE(outer_var_shadow) -- cgit v1.2.3-55-g6feb