From ddb0b9deb720368a425d00bce0c0352469b55911 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Mon, 14 Feb 2022 15:35:54 +0800 Subject: fixing issue #77. change table appending syntax to: tb[] = 1 --- src/yuescript/yue_ast.h | 5 +- src/yuescript/yue_compiler.cpp | 193 ++++++++++++++++++++++------------------- src/yuescript/yue_parser.cpp | 6 +- src/yuescript/yue_parser.h | 1 + 4 files changed, 110 insertions(+), 95 deletions(-) (limited to 'src') diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 7762c91..79e35a5 100755 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h @@ -561,11 +561,14 @@ AST_END(Invoke) AST_LEAF(existential_op) AST_END(existential_op) +AST_LEAF(table_appending_op) +AST_END(table_appending_op) + class InvokeArgs_t; AST_NODE(ChainValue) ast_ptr sep; - ast_sel_list items; + ast_sel_list items; AST_MEMBER(ChainValue, &sep, &items) AST_END(ChainValue) diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 6617ec5..6bc9fe8 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.9.9"sv; +const std::string_view version = "0.9.10"sv; const std::string_view extension = "yue"sv; class YueCompilerImpl { @@ -809,6 +809,7 @@ private: switch (lastItem->getId()) { case id(): case id(): + case id(): return true; } } @@ -1212,25 +1213,52 @@ private: BREAK_IF(!value); auto chainValue = value->item.as(); BREAK_IF(!chainValue); - auto dot = ast_cast(chainValue->items.back()); - BREAK_IF(!dot); - BREAK_IF(!dot->name.is()); - str_list args; - chainValue->items.pop_back(); - if (chainValue->items.empty()) { - if (_withVars.empty()) { - throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x)); + str_list temp; + if (auto dot = ast_cast(chainValue->items.back())) { + BREAK_IF(!dot->name.is()); + str_list args; + chainValue->items.pop_back(); + if (chainValue->items.empty()) { + if (_withVars.empty()) { + throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x)); + } else { + args.push_back(_withVars.top()); + } } else { - args.push_back(_withVars.top()); + transformExp(static_cast(*it), args, ExpUsage::Closure); } - } else { - transformExp(static_cast(*it), args, ExpUsage::Closure); - } - if (vit != values.end()) transformAssignItem(*vit, args); - else args.push_back("nil"s); - _buf << indent() << globalVar("setmetatable"sv, x) << '(' << join(args, ", "sv) << ')' << nll(x); - str_list temp; - temp.push_back(clearBuf()); + if (vit != values.end()) transformAssignItem(*vit, args); + else args.push_back("nil"s); + _buf << indent() << globalVar("setmetatable"sv, x) << '(' << join(args, ", "sv) << ')' << nll(x); + temp.push_back(clearBuf()); + } else if (ast_is(chainValue->items.back())) { + chainValue->items.pop_back(); + auto varName = singleVariableFrom(chainValue); + bool isScoped = false; + if (varName.empty() || !isLocal(varName)) { + isScoped = true; + temp.push_back(indent() + "do"s + nll(x)); + pushScope(); + auto objVar = getUnusedName("_obj_"sv); + auto newAssignment = x->new_ptr(); + newAssignment->expList.set(toAst(objVar, x)); + auto assign = x->new_ptr(); + assign->values.push_back(*it); + newAssignment->action.set(assign); + transformAssignment(newAssignment, temp); + varName = objVar; + } + auto newAssignment = x->new_ptr(); + newAssignment->expList.set(toAst(varName + "[#"s + varName + "+1]"s, x)); + auto assign = x->new_ptr(); + assign->values.push_back(*vit); + newAssignment->action.set(assign); + transformAssignment(newAssignment, temp); + if (isScoped) { + popScope(); + temp.push_back(indent() + "end"s + nlr(x)); + } + } else break; auto newExpList = x->new_ptr(); auto newAssign = x->new_ptr(); auto newAssignment = x->new_ptr(); @@ -1243,7 +1271,7 @@ private: if (value != *vit) newAssign->values.push_back(value); } if (newExpList->exprs.empty() && newAssign->values.empty()) { - out.push_back(temp.back()); + out.push_back(join(temp)); return; } if (newExpList->exprs.size() < newAssign->values.size()) { @@ -2016,81 +2044,67 @@ private: if (!leftValue) throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, leftExp)); auto chain = leftValue->item.as(); if (!chain) throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, chain)); - auto op = _parser.toString(update->op); + BLOCK_START { auto dot = ast_cast(chain->items.back()); if (dot && dot->name.is()) { throw std::logic_error(_info.errorMessage("can not apply update to a metatable"sv, leftExp)); } - BLOCK_START - if (op == "#"sv) { - auto varName = singleVariableFrom(chain); - BREAK_IF(!varName.empty() && isLocal(varName)); - auto objVar = getUnusedName("_obj_"sv); - auto newAssignment = x->new_ptr(); - newAssignment->expList.set(toAst(objVar, x)); - auto assign = x->new_ptr(); - assign->values.push_back(leftExp); - newAssignment->action.set(assign); - transformAssignment(newAssignment, temp); - chain->items.clear(); - chain->items.push_back(toAst(objVar, x)); - } else { - BREAK_IF(chain->items.size() < 2); - if (chain->items.size() == 2) { - if (auto callable = ast_cast(chain->items.front())) { - ast_node* var = callable->item.as(); - if (auto self = callable->item.as()) { - var = self->name.as(); - } - BREAK_IF(var && isLocal(_parser.toString(var))); + BREAK_IF(chain->items.size() < 2); + if (chain->items.size() == 2) { + if (auto callable = ast_cast(chain->items.front())) { + ast_node* var = callable->item.as(); + if (auto self = callable->item.as()) { + var = self->name.as(); } + BREAK_IF(var && isLocal(_parser.toString(var))); } - auto tmpChain = x->new_ptr(); - ast_ptr ptr(chain->items.back()); - for (auto item : chain->items.objects()) { - if (item != ptr) { - tmpChain->items.push_back(item); - } - } - auto value = x->new_ptr(); - value->item.set(tmpChain); - auto exp = newExp(value, x); - auto objVar = getUnusedName("_obj_"sv); - auto newAssignment = x->new_ptr(); - newAssignment->expList.set(toAst(objVar, x)); - auto assign = x->new_ptr(); - assign->values.push_back(exp); - newAssignment->action.set(assign); - transformAssignment(newAssignment, temp); - chain->items.clear(); - chain->items.push_back(toAst(objVar, x)); - chain->items.push_back(ptr); } - BLOCK_END auto tmpChain = x->new_ptr(); + ast_ptr ptr(chain->items.back()); for (auto item : chain->items.objects()) { - bool itemAdded = false; - BLOCK_START - auto exp = ast_cast(item); - BREAK_IF(!exp); - auto var = singleVariableFrom(exp); - BREAK_IF(!var.empty()); - auto upVar = getUnusedName("_update_"sv); - auto newAssignment = x->new_ptr(); - newAssignment->expList.set(toAst(upVar, x)); - auto assign = x->new_ptr(); - assign->values.push_back(exp); - newAssignment->action.set(assign); - transformAssignment(newAssignment, temp); - tmpChain->items.push_back(toAst(upVar, x)); - itemAdded = true; - BLOCK_END - if (!itemAdded) tmpChain->items.push_back(item); + if (item != ptr) { + tmpChain->items.push_back(item); + } } + auto value = x->new_ptr(); + value->item.set(tmpChain); + auto exp = newExp(value, x); + auto objVar = getUnusedName("_obj_"sv); + auto newAssignment = x->new_ptr(); + newAssignment->expList.set(toAst(objVar, x)); + auto assign = x->new_ptr(); + assign->values.push_back(exp); + newAssignment->action.set(assign); + transformAssignment(newAssignment, temp); chain->items.clear(); - chain->items.dup(tmpChain->items); + chain->items.push_back(toAst(objVar, x)); + chain->items.push_back(ptr); } + BLOCK_END + auto tmpChain = x->new_ptr(); + for (auto item : chain->items.objects()) { + bool itemAdded = false; + BLOCK_START + auto exp = ast_cast(item); + BREAK_IF(!exp); + auto var = singleVariableFrom(exp); + BREAK_IF(!var.empty()); + auto upVar = getUnusedName("_update_"sv); + auto newAssignment = x->new_ptr(); + newAssignment->expList.set(toAst(upVar, x)); + auto assign = x->new_ptr(); + assign->values.push_back(exp); + newAssignment->action.set(assign); + transformAssignment(newAssignment, temp); + tmpChain->items.push_back(toAst(upVar, x)); + itemAdded = true; + BLOCK_END + if (!itemAdded) tmpChain->items.push_back(item); + } + chain->items.clear(); + chain->items.dup(tmpChain->items); + auto op = _parser.toString(update->op); if (op == "??"sv) { auto defs = getPredefine(assignment); auto rightExp = x->new_ptr(); @@ -2101,16 +2115,6 @@ private: if (!defs.empty()) temp.back().insert(0, defs + nll(x)); out.push_back(join(temp)); return; - } else if (op == "#"sv) { - auto left = _parser.toString(chain->items.front()); - auto newAssignment = x->new_ptr(); - newAssignment->expList.set(toAst(left + "[#"s + left + "+1]"s, x)); - auto assign = x->new_ptr(); - assign->values.push_back(update->value); - newAssignment->action.set(assign); - transformAssignment(newAssignment, temp); - out.push_back(join(temp)); - return; } auto defs = getPredefine(assignment); transformValue(leftValue, temp); @@ -3970,6 +3974,9 @@ private: temp.back() = (temp.back().front() == '[' ? "[ "s : "["s) + temp.back() + ']'; break; case id(): transformInvokeArgs(static_cast(item), temp); break; + case id(): + transform_table_appending_op(static_cast(item), temp); + break; default: YUEE("AST node mismatch", item); break; } } @@ -4391,6 +4398,10 @@ private: throw std::logic_error(_info.errorMessage("slice syntax not supported here"sv, slice)); } + void transform_table_appending_op(table_appending_op_t* op, str_list&) { + throw std::logic_error(_info.errorMessage("table appending syntax not supported here"sv, op)); + } + void transformInvoke(Invoke_t* invoke, str_list& out) { str_list temp; for (auto arg : invoke->args.objects()) { diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 772ae08..3d12190 100755 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -324,8 +324,7 @@ YueParser::YueParser() { expr("|") | expr(">>") | expr("<<") | - expr("??") | - expr("#"); + expr("??"); Update = Space >> update_op >> expr("=") >> Exp; @@ -382,7 +381,7 @@ YueParser::YueParser() { return st->chainBlockStack.empty() || st->chainBlockStack.top(); }) >> +SpaceBreak >> Advance >> ensure( chain_line >> *(+SpaceBreak >> chain_line), PopIndent); - ChainValue = Seperator >> (Chain | Callable) >> -existential_op >> -(InvokeArgs | chain_block); + ChainValue = Seperator >> (Chain | Callable) >> -existential_op >> -(InvokeArgs | chain_block) >> -table_appending_op; simple_table = Seperator >> KeyValue >> *(sym(',') >> KeyValue); Value = SimpleValue | simple_table | ChainValue | String; @@ -427,6 +426,7 @@ YueParser::YueParser() { Metamethod = Name >> expr('#'); existential_op = expr('?') >> not_(expr('?')); + table_appending_op = expr("[]"); chain_call = (Callable | String) >> -existential_op >> ChainItems; chain_item = and_(set(".\\")) >> ChainItems; chain_dot_chain = DotChainItem >> -existential_op >> -ChainItems; diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index e128e82..7dea126 100755 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h @@ -277,6 +277,7 @@ private: AST_RULE(Slice) AST_RULE(Invoke) AST_RULE(existential_op) + AST_RULE(table_appending_op) AST_RULE(TableLit) AST_RULE(TableBlock) AST_RULE(TableBlockIndent) -- cgit v1.2.3-55-g6feb