From ec26010fd100bb014584653e0e1370dba816fd1f Mon Sep 17 00:00:00 2001 From: Li Jin Date: Thu, 4 Dec 2025 02:57:43 +0800 Subject: Updated reserved comments function. --- src/yuescript/yue_ast.cpp | 64 ++- src/yuescript/yue_ast.h | 21 +- src/yuescript/yue_compiler.cpp | 884 +++++++++++++++++++++-------------------- src/yuescript/yue_parser.cpp | 49 +-- src/yuescript/yue_parser.h | 6 +- src/yuescript/yuescript.cpp | 22 +- 6 files changed, 541 insertions(+), 505 deletions(-) (limited to 'src') diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp index 278d992..7574b06 100644 --- a/src/yuescript/yue_ast.cpp +++ b/src/yuescript/yue_ast.cpp @@ -203,9 +203,16 @@ std::string YueLineComment_t::to_string(void* ud) const { auto info = reinterpret_cast(ud); return "--"s + info->convert(this); } -std::string MultilineCommentInner_t::to_string(void* ud) const { +std::string YueMultilineComment_t::to_string(void* ud) const { auto info = reinterpret_cast(ud); - return info->convert(this); + return "--[["s + info->convert(this) + "]]"s; +} +std::string YueComment_t::to_string(void* ud) const { + if (comment) { + return comment->to_string(ud); + } else { + return {}; + } } std::string Variable_t::to_string(void* ud) const { return name->to_string(ud); @@ -1596,38 +1603,15 @@ std::string StatementAppendix_t::to_string(void* ud) const { return item->to_string(ud); } std::string Statement_t::to_string(void* ud) const { - std::string line; - if (!comments.empty()) { - auto info = reinterpret_cast(ud); - str_list temp; - for (ast_node* comment : comments.objects()) { - if (comment == comments.front()) { - temp.push_back(comment->to_string(ud)); - } else { - temp.push_back(info->ind() + comment->to_string(ud)); - } - } - if (appendix) { - temp.push_back(info->ind() + content->to_string(ud) + ' ' + appendix->to_string(ud)); - return join(temp, "\n"sv); - } else { - temp.push_back(info->ind() + content->to_string(ud)); - return join(temp, "\n"sv); - } + if (appendix) { + return content->to_string(ud) + ' ' + appendix->to_string(ud); } else { - if (appendix) { - return content->to_string(ud) + ' ' + appendix->to_string(ud); - } else { - return content->to_string(ud); - } + return content->to_string(ud); } } std::string StatementSep_t::to_string(void*) const { return {}; } -std::string YueMultilineComment_t::to_string(void* ud) const { - return "--[["s + inner->to_string(ud) + "]]"s; -} std::string ChainAssign_t::to_string(void* ud) const { str_list temp; for (auto exp : exprs.objects()) { @@ -1641,14 +1625,22 @@ std::string Body_t::to_string(void* ud) const { std::string Block_t::to_string(void* ud) const { auto info = reinterpret_cast(ud); str_list temp; - for (auto stmt_ : statements.objects()) { - auto stmt = static_cast(stmt_); - if (stmt->content.is()) { - info->pushScope(); - temp.emplace_back(stmt->to_string(ud)); - info->popScope(); - } else { - temp.emplace_back(info->ind() + stmt->to_string(ud)); + for (auto stmt_ : statementOrComments.objects()) { + if (auto stmt = ast_cast(stmt_)) { + if (stmt->content.is()) { + info->pushScope(); + temp.emplace_back(stmt->to_string(ud)); + info->popScope(); + } else { + temp.emplace_back(info->ind() + stmt->to_string(ud)); + } + } else if (info->reserveComment) { + auto comment = ast_to(stmt_); + if (comment->comment) { + temp.emplace_back(info->ind() + comment->to_string(ud)); + } else { + temp.emplace_back(comment->to_string(ud)); + } } } return join(temp, "\n"sv); diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 3aca702..df852bd 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h @@ -929,14 +929,14 @@ AST_END(StatementSep) AST_LEAF(YueLineComment) AST_END(YueLineComment) -AST_LEAF(MultilineCommentInner) -AST_END(MultilineCommentInner) - -AST_NODE(YueMultilineComment) - ast_ptr inner; - AST_MEMBER(YueMultilineComment, &inner) +AST_LEAF(YueMultilineComment) AST_END(YueMultilineComment) +AST_NODE(YueComment) + ast_sel comment; + AST_MEMBER(YueComment, &comment) +AST_END(YueComment) + AST_NODE(ChainAssign) ast_ptr sep; ast_list exprs; @@ -945,8 +945,6 @@ AST_NODE(ChainAssign) AST_END(ChainAssign) AST_NODE(Statement) - ast_ptr sep; - ast_sel_list comments; ast_sel content; ast_ptr appendix; - AST_MEMBER(Statement, &sep, &comments, &content, &appendix) + AST_MEMBER(Statement, &content, &appendix) AST_END(Statement) AST_NODE(Body) @@ -964,8 +962,8 @@ AST_END(Body) AST_NODE(Block) ast_ptr sep; - ast_list statements; - AST_MEMBER(Block, &sep, &statements) + ast_sel_list statementOrComments; + AST_MEMBER(Block, &sep, &statementOrComments) AST_END(Block) AST_NODE(BlockEnd) @@ -984,6 +982,7 @@ struct YueFormat { int indent = 0; bool spaceOverTab = false; int tabSpaces = 4; + bool reserveComment = true; std::string toString(ast_node* node); void pushScope(); diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 84b990f..8d3899f 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -78,7 +78,7 @@ static std::unordered_set Metamethods = { "close"s // Lua 5.4 }; -const std::string_view version = "0.30.0"sv; +const std::string_view version = "0.30.1"sv; const std::string_view extension = "yue"sv; class CompileError : public std::logic_error { @@ -182,8 +182,9 @@ public: try { auto block = _info.node.to()->block.get(); if (_info.exportMacro) { - for (auto stmt_ : block->statements.objects()) { - auto stmt = static_cast(stmt_); + for (auto stmt_ : block->statementOrComments.objects()) { + auto stmt = ast_cast(stmt_); + if (!stmt) continue; switch (stmt->content->get_id()) { case id(): case id(): @@ -967,7 +968,7 @@ private: } } - const std::string nll(ast_node* node) const { + const std::string nl(ast_node* node) const { if (_config.reserveLineNumber) { return " -- "s + std::to_string(node->m_begin.m_line + _config.lineOffset) + _newLine; } else { @@ -975,14 +976,6 @@ private: } } - const std::string nlr(ast_node* node) const { - if (_config.reserveLineNumber) { - return " -- "s + std::to_string(node->m_end.m_line + _config.lineOffset) + _newLine; - } else { - return _newLine; - } - } - void incIndentOffset() { _indentOffset++; } @@ -1169,14 +1162,22 @@ private: return nullptr; } - Statement_t* lastStatementFrom(const node_container& stmts) const { - if (!stmts.empty()) { - auto it = stmts.end(); - --it; - while (!static_cast(*it)->content && it != stmts.begin()) { - --it; + Statement_t* lastStatementFrom(const node_container& statementOrComments) const { + if (!statementOrComments.empty()) { + for (auto it = statementOrComments.rbegin(); it != statementOrComments.rend(); ++it) { + if (auto stmt = ast_cast(*it)) { + return stmt; + } + } + } + return nullptr; + } + + Statement_t* firstStatementFrom(Block_t* block) const { + for (auto stmt_ : block->statementOrComments.objects()) { + if (auto stmt = ast_cast(stmt_)) { + return stmt; } - return static_cast(*it); } return nullptr; } @@ -1185,16 +1186,26 @@ private: if (auto stmt = body->content.as()) { return stmt; } else { - const auto& stmts = body->content.to()->statements.objects(); + const auto& stmts = body->content.to()->statementOrComments.objects(); return lastStatementFrom(stmts); } } Statement_t* lastStatementFrom(Block_t* block) const { - const auto& stmts = block->statements.objects(); + const auto& stmts = block->statementOrComments.objects(); return lastStatementFrom(stmts); } + int countStatementFrom(Block_t* block) const { + int count = 0; + for (auto stmt_ : block->statementOrComments.objects()) { + if (ast_is(stmt_)) { + count++; + } + } + return count; + } + Exp_t* lastExpFromAssign(ast_node* action) { switch (action->get_id()) { case id(): { @@ -1646,24 +1657,31 @@ private: return; } - void transformStatement(Statement_t* statement, str_list& out) { - auto x = statement; - if (_config.reserveComment && !x->comments.empty()) { - for (ast_node* node : x->comments.objects()) { - switch (node->get_id()) { - case id(): { - auto comment = ast_cast(node); - out.push_back(indent() + "--"s + _parser.toString(comment) + '\n'); - break; - } - case id(): { - auto comment = ast_cast(node); - out.push_back(indent() + _parser.toString(comment) + '\n'); - break; - } - } + void transformComment(YueComment_t* comment, str_list& out) { + if (!_config.reserveComment) { + return; + } + auto node = comment->comment.get(); + if (!node) { + out.push_back("\n"s); + return; + } + switch (node->get_id()) { + case id(): { + auto content = static_cast(node); + out.push_back(indent() + "--"s + _parser.toString(content) + '\n'); + break; + } + case id(): { + auto content = static_cast(node); + out.push_back(indent() + "--[["s + _parser.toString(content) + "]]\n"s); + break; } } + } + + void transformStatement(Statement_t* statement, str_list& out) { + auto x = statement; if (statement->appendix) { if (auto assignment = assignmentFrom(statement)) { auto preDefine = getPreDefineLine(assignment); @@ -2047,7 +2065,7 @@ private: std::string getPreDefineLine(ExpListAssign_t* assignment) { auto preDefine = getPreDefine(assignment); - if (!preDefine.empty()) preDefine += nll(assignment); + if (!preDefine.empty()) preDefine += nl(assignment); return preDefine; } @@ -2203,14 +2221,14 @@ private: temp.push_back(getPreDefineLine(assignment)); bool needScope = !currentScope().lastStatement; if (needScope) { - temp.push_back(indent() + "do"s + nll(assignment)); + temp.push_back(indent() + "do"s + nl(assignment)); pushScope(); } transformAssignment(preAssignment, temp); transformAssignment(assignment, temp); if (needScope) { popScope(); - temp.push_back(indent() + "end"s + nll(assignment)); + temp.push_back(indent() + "end"s + nl(assignment)); } out.push_back(join(temp)); return false; @@ -2280,7 +2298,7 @@ private: throw CompileError("right value missing"sv, values.front()); } transformAssignItem(*vit, args); - _buf << indent() << globalVar("setmetatable"sv, x, AccessType::Read) << '(' << join(args, ", "sv) << ')' << nll(x); + _buf << indent() << globalVar("setmetatable"sv, x, AccessType::Read) << '(' << join(args, ", "sv) << ')' << nl(x); temp.push_back(clearBuf()); if (!afterAssignment->expList->exprs.empty()) { transformAssignment(afterAssignment, temp); @@ -2309,7 +2327,7 @@ private: if (varName.empty() || !isLocal(varName)) { if (needScope) { extraScoped = true; - temp.push_back(indent() + "do"s + nll(x)); + temp.push_back(indent() + "do"s + nl(x)); pushScope(); } auto objVar = getUnusedName("_obj_"sv); @@ -2324,7 +2342,7 @@ private: if (auto spread = ast_cast(*vit)) { auto lenVar = getUnusedName("_len_"sv); forceAddToScope(lenVar); - temp.push_back(indent() + "local "s + lenVar + " = #"s + varName + " + 1"s + nll(spread)); + temp.push_back(indent() + "local "s + lenVar + " = #"s + varName + " + 1"s + nl(spread)); auto elmVar = getUnusedName("_elm_"sv); _buf << varName << '[' << lenVar << "],"s << lenVar << "="s << elmVar << ',' << lenVar << "+1 for "s << elmVar << " in *nil"s; auto stmt = toAst(clearBuf(), spread); @@ -2344,7 +2362,7 @@ private: } if (extraScoped) { popScope(); - temp.push_back(indent() + "end"s + nlr(x)); + temp.push_back(indent() + "end"s + nl(x)); } if (!afterAssignment->expList->exprs.empty()) { transformAssignment(afterAssignment, temp); @@ -2615,11 +2633,11 @@ private: checkConst(def, x); addToScope(def); } - temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); + temp.push_back(indent() + "local "s + join(defs, ", "sv) + nl(x)); } if (needScope) { extraScope = true; - temp.push_back(indent() + "do"s + nll(x)); + temp.push_back(indent() + "do"s + nl(x)); pushScope(); } } @@ -2671,13 +2689,13 @@ private: continue; } if (extraScope) { - temp.push_back(indent() + "do"s + nll(x)); + temp.push_back(indent() + "do"s + nl(x)); pushScope(); } if (!pair.targetVar.empty()) { checkConst(pair.targetVar, x); if (addToScope(pair.targetVar)) { - _buf << indent() << "local "sv << pair.targetVar << nll(x); + _buf << indent() << "local "sv << pair.targetVar << nl(x); temp.push_back(clearBuf()); } } @@ -2687,7 +2705,7 @@ private: objVar = destruct.valueVar; } else { if (needScope) { - temp.push_back(indent() + "do"s + nll(x)); + temp.push_back(indent() + "do"s + nl(x)); pushScope(); } objVar = getUnusedName("_obj_"sv); @@ -2703,7 +2721,7 @@ private: if (!isLocalValue) { if (needScope) { popScope(); - _buf << indent() << "end"sv << nlr(x); + _buf << indent() << "end"sv << nl(x); temp.push_back(clearBuf()); } } @@ -2741,9 +2759,9 @@ private: checkConst(def, x); addToScope(def); } - temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); + temp.push_back(indent() + "local "s + join(defs, ", "sv) + nl(x)); } - temp.push_back(indent() + "do"s + nll(x)); + temp.push_back(indent() + "do"s + nl(x)); pushScope(); } } else { @@ -2752,11 +2770,11 @@ private: checkConst(def, x); addToScope(def); } - temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); + temp.push_back(indent() + "local "s + join(defs, ", "sv) + nl(x)); } if (needScope) { extraScope = true; - temp.push_back(indent() + "do"s + nll(x)); + temp.push_back(indent() + "do"s + nl(x)); pushScope(); } auto valVar = getUnusedName("_obj_"sv); @@ -2771,7 +2789,7 @@ private: if (destruct.inlineAssignment) { if (needScope && !extraScope) { extraScope = true; - temp.push_back(indent() + "do"s + nll(x)); + temp.push_back(indent() + "do"s + nl(x)); pushScope(); } transformAssignment(destruct.inlineAssignment, temp); @@ -2836,13 +2854,13 @@ private: } if (extraScope) { popScope(); - _buf << indent() << "end"sv << nlr(x); + _buf << indent() << "end"sv << nl(x); temp.push_back(clearBuf()); } } if (extraScope) { popScope(); - temp.push_back(indent() + "end"s + nlr(x)); + temp.push_back(indent() + "end"s + nl(x)); } out.push_back(join(temp)); if (assignment->expList->followStmt) { @@ -3664,7 +3682,7 @@ private: _buf << defs; else _buf << indent() << left; - _buf << " = "sv << left << ' ' << op << ' ' << right << nll(assignment); + _buf << " = "sv << left << ' ' << op << ' ' << right << nl(assignment); out.push_back(clearBuf()); break; } @@ -3711,9 +3729,9 @@ private: transformExpList(expList, temp); std::string left = std::move(temp.back()); temp.pop_back(); - out.push_back(indent() + left + " = "s + join(temp, ", "sv) + nll(assignment)); + out.push_back(indent() + left + " = "s + join(temp, ", "sv) + nl(assignment)); } else { - out.push_back(preDefine + " = "s + join(temp, ", "sv) + nll(assignment)); + out.push_back(preDefine + " = "s + join(temp, ", "sv) + nl(assignment)); } } else { std::string preDefine = toLocalDecl(defs); @@ -3729,7 +3747,7 @@ private: for (auto value : assign->values.objects()) { transformAssignItem(value, temp); } - out.push_back((preDefine.empty() ? Empty : preDefine + nll(assignment)) + indent() + left + " = "s + join(temp, ", "sv) + nll(assignment)); + out.push_back((preDefine.empty() ? Empty : preDefine + nl(assignment)) + indent() + left + " = "s + join(temp, ", "sv) + nl(assignment)); } break; } @@ -3830,7 +3848,7 @@ private: if (usage != ExpUsage::Closure) { if (!currentScope().lastStatement) { extraScope = true; - temp.push_back(indent() + "do"s + nll(asmt)); + temp.push_back(indent() + "do"s + nl(asmt)); pushScope(); } } @@ -3863,7 +3881,7 @@ private: if (usage != ExpUsage::Closure) { if (!currentScope().lastStatement) { extraScope = true; - temp.push_back(indent() + "do"s + nll(asmt)); + temp.push_back(indent() + "do"s + nl(asmt)); pushScope(); } } @@ -3892,12 +3910,12 @@ private: if (pair != ifCondPairs.front()) { _buf << "else"sv; } - _buf << "if "sv << condStr << " then"sv << nll(condition); + _buf << "if "sv << condStr << " then"sv << nl(condition); temp.push_back(clearBuf()); } if (pair.second) { if (!pair.first) { - temp.push_back(indent() + "else"s + nll(pair.second)); + temp.push_back(indent() + "else"s + nl(pair.second)); } pushScope(); if (pair == ifCondPairs.front() && extraAssignment) { @@ -3907,17 +3925,17 @@ private: popScope(); } if (!pair.first) { - temp.push_back(indent() + "end"s + nll(nodes.front())); + temp.push_back(indent() + "end"s + nl(nodes.front())); break; } } if (extraScope) { popScope(); - temp.push_back(indent() + "end"s + nlr(nodes.front())); + temp.push_back(indent() + "end"s + nl(nodes.front())); } if (usage == ExpUsage::Closure) { popScope(); - *funcStart = anonFuncStart() + nll(nodes.front()); + *funcStart = anonFuncStart() + nl(nodes.front()); temp.push_back(indent() + anonFuncEnd()); popAnonVarArg(); popFunctionScope(); @@ -4012,7 +4030,7 @@ private: } else { transformExp(arg, out, ExpUsage::Closure); out.back().insert(0, indent()); - out.back().append(nlr(x)); + out.back().append(nl(x)); } return; } @@ -4136,7 +4154,7 @@ private: auto stmt = exp->new_ptr(); stmt->content.set(preDefine); preDefine.set(nullptr); - block->statements.push_back(stmt); + block->statementOrComments.push_back(stmt); auto simpleValue = exp->new_ptr(); simpleValue->value.set(ifNode); auto explist = exp->new_ptr(); @@ -4145,7 +4163,7 @@ private: expListAssign->expList.set(explist); stmt = exp->new_ptr(); stmt->content.set(expListAssign); - block->statements.push_back(stmt); + block->statementOrComments.push_back(stmt); nodes->push_back(block); nodes = &ifNode->nodes; } else { @@ -4153,7 +4171,7 @@ private: auto stmt = exp->new_ptr(); stmt->content.set(preDefine); preDefine.set(nullptr); - block->statements.push_back(stmt); + block->statementOrComments.push_back(stmt); auto simpleValue = exp->new_ptr(); simpleValue->value.set(ifNode); auto explist = exp->new_ptr(); @@ -4162,7 +4180,7 @@ private: expListAssign->expList.set(explist); stmt = exp->new_ptr(); stmt->content.set(expListAssign); - block->statements.push_back(stmt); + block->statementOrComments.push_back(stmt); auto body = exp->new_ptr(); body->content.set(block); auto doNode = exp->new_ptr(); @@ -4324,7 +4342,7 @@ private: auto stmt = x->new_ptr(); stmt->content.set(expListAssign); auto blk = x->new_ptr(); - blk->statements.push_back(stmt); + blk->statementOrComments.push_back(stmt); newBlock.set(blk); } if (!globals.empty()) { @@ -4420,9 +4438,9 @@ private: if (auto sVal = simpleSingleValueFrom(exp)) { if (auto doNode = sVal->value.as()) { if (auto blk = doNode->body->content.as()) { - block->statements.dup(blk->statements); + block->statementOrComments.dup(blk->statementOrComments); } else { - block->statements.push_back(doNode->body->content.to()); + block->statementOrComments.push_back(doNode->body->content.to()); } return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite); } @@ -4434,7 +4452,7 @@ private: returnNode->valueList.set(returnList); auto stmt = exp->new_ptr(); stmt->content.set(returnNode); - block->statements.push_back(stmt); + block->statementOrComments.push_back(stmt); return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite); } return std::nullopt; @@ -4491,7 +4509,7 @@ private: bool extraScope = !currentScope().lastStatement; if (forAssignment) { if (extraScope) { - temp.push_back(indent() + "do"s + nll(x)); + temp.push_back(indent() + "do"s + nl(x)); pushScope(); } } @@ -4514,9 +4532,9 @@ private: case ExpUsage::Return: case ExpUsage::Closure: { prepareValue(); - _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); - _buf << indent(1) << "return "s << objVar << nll(x); - _buf << indent() << "else"s << nll(x); + _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nl(x); + _buf << indent(1) << "return "s << objVar << nl(x); + _buf << indent() << "else"s << nl(x); temp.push_back(clearBuf()); auto ret = x->new_ptr(); ret->explicitReturn = false; @@ -4526,10 +4544,10 @@ private: incIndentOffset(); transformReturn(ret, temp); decIndentOffset(); - temp.push_back(indent() + "end"s + nll(x)); + temp.push_back(indent() + "end"s + nl(x)); if (usage == ExpUsage::Closure) { popScope(); - *funcStart = anonFuncStart() + nll(x); + *funcStart = anonFuncStart() + nl(x); temp.push_back(indent() + anonFuncEnd()); popAnonVarArg(); popFunctionScope(); @@ -4546,14 +4564,14 @@ private: assign->values.push_back(exp); temp.push_back(getPreDefineLine(assignment)); extraScope = prepareValue(true); - _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); + _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nl(x); temp.push_back(clearBuf()); pushScope(); assign->values.clear(); assign->values.push_back(toAst(objVar, x)); transformAssignment(assignment, temp); popScope(); - temp.push_back(indent() + "else"s + nll(x)); + temp.push_back(indent() + "else"s + nl(x)); assign->values.clear(); assign->values.push_back(exp->nilCoalesed); } else { @@ -4561,17 +4579,17 @@ private: assign->values.push_back(exp->nilCoalesed); temp.push_back(getPreDefineLine(assignment)); transformExp(left, temp, ExpUsage::Closure); - _buf << indent() << "if "sv << temp.back() << " == nil then"sv << nll(x); + _buf << indent() << "if "sv << temp.back() << " == nil then"sv << nl(x); temp.pop_back(); temp.push_back(clearBuf()); } pushScope(); transformAssignment(assignment, temp); popScope(); - temp.push_back(indent() + "end"s + nlr(x)); + temp.push_back(indent() + "end"s + nl(x)); if (extraScope) { popScope(); - temp.push_back(indent() + "end"s + nlr(x)); + temp.push_back(indent() + "end"s + nl(x)); } break; } @@ -4670,11 +4688,11 @@ private: switch (content->get_id()) { case id(): { auto block = static_cast(content); - newBlock->statements.dup(block->statements); + newBlock->statementOrComments.dup(block->statementOrComments); break; } case id(): { - newBlock->statements.push_back(content); + newBlock->statementOrComments.push_back(content); break; } default: YUEE("AST node mismatch", content); break; @@ -4686,7 +4704,7 @@ private: returnNode->valueList.set(funLit->defaultReturn); auto stmt = newBlock->new_ptr(); stmt->content.set(returnNode); - newBlock->statements.push_back(stmt); + newBlock->statementOrComments.push_back(stmt); } transformBlock(newBlock, temp, ExpUsage::Common); } else { @@ -4708,7 +4726,7 @@ private: } _buf << args << ')'; if (!initArgs.empty() || !bodyCodes.empty()) { - _buf << nlr(argsDef) << initArgs << bodyCodes; + _buf << nl(argsDef) << initArgs << bodyCodes; popScope(); _buf << indent() << "end"sv; } else { @@ -4719,7 +4737,7 @@ private: auto& bodyCodes = temp.back(); _buf << "function("sv << (isFatArrow ? "self"s : Empty) << ')'; if (!bodyCodes.empty()) { - _buf << nll(funLit) << bodyCodes; + _buf << nl(funLit) << bodyCodes; popScope(); _buf << indent() << "end"sv; } else { @@ -4736,7 +4754,7 @@ private: auto x = body; if (auto stmt = body->content.as()) { auto block = x->new_ptr(); - block->statements.push_back(stmt); + block->statementOrComments.push_back(stmt); transformBlock(block, out, usage, assignList); } else { transformBlock(body->content.to(), out, usage, assignList); @@ -4748,13 +4766,15 @@ private: out.push_back(Empty); return; } - const auto& nodes = block->statements.objects(); + const auto& nodes = block->statementOrComments.objects(); + auto lastStmt = lastStatementFrom(nodes); LocalMode mode = LocalMode::None; Local_t *any = nullptr, *capital = nullptr; for (auto it = nodes.begin(); it != nodes.end(); ++it) { auto node = *it; - auto stmt = static_cast(node); - if (!stmt->appendix && stmt->content.is() && stmt != nodes.back()) { + auto stmt = ast_cast(node); + if (!stmt) continue; + if (!stmt->appendix && stmt->content.is() && stmt != lastStmt) { throw CompileError("'return' statement must be the last line in the block"sv, stmt->content); } else if (auto pipeBody = stmt->content.as()) { auto x = stmt; @@ -4763,6 +4783,16 @@ private: BREAK_IF(it == nodes.begin()); auto last = it; --last; + bool found = true; + while (!ast_is(*last)) { + if (last == nodes.begin()) { + found = false; + break; + } else { + --last; + } + } + BREAK_IF(!found); auto lst = static_cast(*last); if (lst->appendix) { throw CompileError("statement decorator must be placed at the end of pipe chain"sv, lst->appendix.get()); @@ -4780,9 +4810,17 @@ private: stmt->content.set(nullptr); auto next = it; ++next; + Statement_t* nextStmt = nullptr; + while (next != nodes.end()) { + nextStmt = ast_cast(*next); + if (nextStmt) { + break; + } + ++next; + } BLOCK_START - BREAK_IF(next == nodes.end()); - BREAK_IF(!static_cast(*next)->content.as()); + BREAK_IF(!nextStmt); + BREAK_IF(!nextStmt->content.as()); throw CompileError("indent mismatch in pipe chain"sv, *next); BLOCK_END } else if (auto backcall = stmt->content.as()) { @@ -4790,7 +4828,7 @@ private: auto newBlock = x->new_ptr(); if (it != nodes.begin()) { for (auto i = nodes.begin(); i != it; ++i) { - newBlock->statements.push_back(*i); + newBlock->statementOrComments.push_back(*i); } } x = backcall; @@ -4801,7 +4839,7 @@ private: ++next; if (next != nodes.end()) { for (auto i = next; i != nodes.end(); ++i) { - block->statements.push_back(*i); + block->statementOrComments.push_back(*i); } } auto body = x->new_ptr(); @@ -4853,7 +4891,7 @@ private: expListAssign->expList.set(expList); newStmt->content.set(expListAssign); newStmt->appendix.set(stmt->appendix); - newBlock->statements.push_back(newStmt); + newBlock->statementOrComments.push_back(newStmt); } transformBlock(newBlock, out, usage, assignList, isRoot); return; @@ -4909,7 +4947,7 @@ private: auto newBlock = x->new_ptr(); if (it != nodes.begin()) { for (auto i = nodes.begin(); i != it; ++i) { - newBlock->statements.push_back(*i); + newBlock->statementOrComments.push_back(*i); } } x = expListAssign; @@ -4919,7 +4957,7 @@ private: ++next; if (next != nodes.end()) { for (auto i = next; i != nodes.end(); ++i) { - followingBlock->statements.push_back(*i); + followingBlock->statementOrComments.push_back(*i); } } } @@ -4947,7 +4985,7 @@ private: newAssignment->action.set(newAssign); auto newStatement = x->new_ptr(); newStatement->content.set(newAssignment); - followingBlock->statements.push_front(newStatement); + followingBlock->statementOrComments.push_front(newStatement); } argNames.push_back("..."s); auto newBody = x->new_ptr(); @@ -4961,8 +4999,9 @@ private: finalArgs.push_back(arg); } } - newBlock->statements.push_back(toAst(funcName + ' ' + (finalArgs.empty() ? "nil"s : join(finalArgs, ","sv)), x)); - auto sVal = singleValueFrom(static_cast(newBlock->statements.back())->content.to()->expList); + auto lastNewStmt = toAst(funcName + ' ' + (finalArgs.empty() ? "nil"s : join(finalArgs, ","sv)), x); + newBlock->statementOrComments.push_back(lastNewStmt); + auto sVal = singleValueFrom(lastNewStmt->content.to()->expList); auto invokArgs = ast_to(sVal->item.to()->items.back()); if (finalArgs.empty()) { invokArgs->args.clear(); @@ -4992,7 +5031,7 @@ private: newItemListAssign->expList.set(newItemList); auto newItemStatement = x->new_ptr(); newItemStatement->content.set(newItemListAssign); - newBlock->statements.push_back(newItemStatement); + newBlock->statementOrComments.push_back(newItemStatement); transformBlock(newBlock, out, usage, assignList, isRoot); return; BLOCK_END @@ -5001,11 +5040,11 @@ private: auto newBlock = x->new_ptr(); if (it != nodes.begin()) { for (auto i = nodes.begin(); i != it; ++i) { - newBlock->statements.push_back(*i); + newBlock->statementOrComments.push_back(*i); } } localAttrib->attrib.set(localAttrib->new_ptr()); - newBlock->statements.push_back(*it); + newBlock->statementOrComments.push_back(*it); x = localAttrib; auto followingBlock = x->new_ptr(); { @@ -5013,7 +5052,7 @@ private: ++next; if (next != nodes.end()) { for (auto i = next; i != nodes.end(); ++i) { - followingBlock->statements.push_back(*i); + followingBlock->statementOrComments.push_back(*i); } } } @@ -5035,13 +5074,13 @@ private: auto value = singleValueFrom(pCallExp); value->item.to()->value.to()->func.set(followingBlock); for (const auto& stmt : getCloses) { - newBlock->statements.push_back(toAst(stmt, x)); + newBlock->statementOrComments.push_back(toAst(stmt, x)); } - newBlock->statements.push_back(pCallStmt); + newBlock->statementOrComments.push_back(pCallStmt); for (const auto& stmt : doCloses) { - newBlock->statements.push_back(toAst(stmt, x)); + newBlock->statementOrComments.push_back(toAst(stmt, x)); } - newBlock->statements.push_back(toAst("if "s + okVar + " then return ... else error ..."s, x)); + newBlock->statementOrComments.push_back(toAst("if "s + okVar + " then return ... else error ..."s, x)); transformBlock(newBlock, out, usage, assignList, isRoot); return; } else if (auto expListAssign = stmt->content.as(); @@ -5050,7 +5089,7 @@ private: auto newBlock = x->new_ptr(); if (it != nodes.begin()) { for (auto i = nodes.begin(); i != it; ++i) { - newBlock->statements.push_back(*i); + newBlock->statementOrComments.push_back(*i); } } auto doBackcall = static_cast(expListAssign->action.get()); @@ -5067,12 +5106,11 @@ private: backcall->value.set(doBackcall->value); auto newStmt = backcall->new_ptr(); newStmt->content.set(backcall); - newStmt->comments.dup(stmt->comments); newStmt->appendix.set(stmt->appendix); - newBlock->statements.push_back(newStmt); + newBlock->statementOrComments.push_back(newStmt); auto ait = it; for (auto i = ++ait; i != nodes.end(); ++i) { - newBlock->statements.push_back(*i); + newBlock->statementOrComments.push_back(*i); } transformBlock(newBlock, out, usage, assignList, isRoot); return; @@ -5184,7 +5222,7 @@ private: } } if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) { - block->statements.push_front(toAst(_info.moduleName + (_info.exportDefault ? "=nil"s : (_info.exportMetatable ? "=<>:{}"s : "={}"s)), block)); + block->statementOrComments.push_front(toAst(_info.moduleName + (_info.exportDefault ? "=nil"s : (_info.exportMetatable ? "=<>:{}"s : "={}"s)), block)); } switch (usage) { case ExpUsage::Closure: @@ -5246,9 +5284,14 @@ private: } if (!nodes.empty()) { str_list temp; + auto lastStmt = lastStatementFrom(nodes); for (auto node : nodes) { + if (auto comment = ast_cast(node)) { + transformComment(comment, temp); + continue; + } auto transformNode = [&]() { - currentScope().lastStatement = (node == nodes.back()) && currentScope().mode == GlobalMode::None; + currentScope().lastStatement = (node == lastStmt) && currentScope().mode == GlobalMode::None; transformStatement(static_cast(node), temp); if (isRoot && !_rootDefs.empty()) { auto last = std::move(temp.back()); @@ -5293,7 +5336,7 @@ private: out.push_back(Empty); } if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) { - out.back().append(indent() + "return "s + _info.moduleName + nlr(block)); + out.back().append(indent() + "return "s + _info.moduleName + nl(block)); } } @@ -5681,12 +5724,12 @@ private: } } transformValue(singleValue, out); - out.back() = indent() + "return "s + out.back() + nlr(returnNode); + out.back() = indent() + "return "s + out.back() + nl(returnNode); return; } else { str_list temp; transformExpListLow(valueList, temp); - out.push_back(indent() + "return "s + temp.back() + nlr(returnNode)); + out.push_back(indent() + "return "s + temp.back() + nl(returnNode)); } } else if (auto tableBlock = returnNode->valueList.as()) { const auto& values = tableBlock->values.objects(); @@ -5694,10 +5737,10 @@ private: transformSpreadTable(values, out, ExpUsage::Return, nullptr, false); } else { transformTable(values, out); - out.back() = indent() + "return "s + out.back() + nlr(returnNode); + out.back() = indent() + "return "s + out.back() + nl(returnNode); } } else { - out.push_back(indent() + "return"s + nll(returnNode)); + out.push_back(indent() + "return"s + nl(returnNode)); } } @@ -5812,9 +5855,9 @@ private: assignment->action.set(assign); transformAssignment(assignment, temp); popScope(); - _buf << indent() << "if "sv << arg.name << " == nil then"sv << nll(def); + _buf << indent() << "if "sv << arg.name << " == nil then"sv << nl(def); _buf << temp.back(); - _buf << indent() << "end"sv << nll(def); + _buf << indent() << "end"sv << nl(def); temp.back() = clearBuf(); } if (arg.assignment) { @@ -5822,7 +5865,7 @@ private: for (const auto& name : names) { forceAddToScope(name); } - temp.emplace_back(indent() + "local "s + join(names, ", "sv) + nll(def)); + temp.emplace_back(indent() + "local "s + join(names, ", "sv) + nl(def)); transformAssignment(arg.assignment, temp); } if (varNames.empty()) @@ -5978,7 +6021,7 @@ private: case ExpUsage::Return: transformParens(parens, out); out.back().insert(0, indent() + "return "s); - out.back().append(nlr(x)); + out.back().append(nl(x)); break; default: transformParens(parens, out); @@ -6049,7 +6092,7 @@ private: } } if (isScoped) { - temp.push_back(indent() + "do"s + nll(x)); + temp.push_back(indent() + "do"s + nl(x)); pushScope(); } objVar = getUnusedName("_obj_"sv); @@ -6109,9 +6152,9 @@ private: _buf << typeVar << "=type "sv << objVar; auto typeAssign = toAst(clearBuf(), partOne); transformAssignment(typeAssign, temp); - _buf << indent() << "if \"table\" == " << typeVar << " or \"userdata\" == "sv << typeVar << " then"sv << nll(x); + _buf << indent() << "if \"table\" == " << typeVar << " or \"userdata\" == "sv << typeVar << " then"sv << nl(x); } else { - _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); + _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nl(x); } temp.push_back(clearBuf()); pushScope(); @@ -6147,15 +6190,15 @@ private: } } popScope(); - temp.push_back(indent() + "end"s + nlr(x)); + temp.push_back(indent() + "end"s + nl(x)); switch (usage) { case ExpUsage::Return: - temp.push_back(indent() + "return nil"s + nlr(x)); + temp.push_back(indent() + "return nil"s + nl(x)); break; case ExpUsage::Closure: - temp.push_back(indent() + "return nil"s + nlr(x)); + temp.push_back(indent() + "return nil"s + nl(x)); popScope(); - *funcStart = anonFuncStart() + nll(x); + *funcStart = anonFuncStart() + nl(x); temp.push_back(indent() + anonFuncEnd()); popAnonVarArg(); popFunctionScope(); @@ -6165,7 +6208,7 @@ private: } if (isScoped) { popScope(); - temp.push_back(indent() + "end"s + nlr(x)); + temp.push_back(indent() + "end"s + nl(x)); } out.push_back(join(temp)); return true; @@ -6182,7 +6225,7 @@ private: switch (usage) { case ExpUsage::Assignment: if (isScoped) { - temp.push_back(indent() + "do"s + nll(x)); + temp.push_back(indent() + "do"s + nl(x)); pushScope(); } break; @@ -6260,12 +6303,12 @@ private: case ExpUsage::Assignment: if (isScoped) { popScope(); - temp.push_back(indent() + "end"s + nlr(x)); + temp.push_back(indent() + "end"s + nl(x)); } break; case ExpUsage::Closure: popScope(); - *funcStart = anonFuncStart() + nll(x); + *funcStart = anonFuncStart() + nl(x); temp.push_back(indent() + anonFuncEnd()); popAnonVarArg(); popFunctionScope(); @@ -6341,7 +6384,7 @@ private: pushScope(); } else if (usage != ExpUsage::Return) { if (isScoped) { - temp.push_back(indent() + "do"s + nll(x)); + temp.push_back(indent() + "do"s + nl(x)); pushScope(); } } @@ -6378,7 +6421,7 @@ private: returnNode->valueList.set(values); transformReturn(returnNode, temp); popScope(); - *funcStart = anonFuncStart() + nll(x); + *funcStart = anonFuncStart() + nl(x); temp.push_back(indent() + anonFuncEnd()); popAnonVarArg(); popFunctionScope(); @@ -6402,7 +6445,7 @@ private: transformAssignment(assignment, temp); if (isScoped) { popScope(); - temp.push_back(indent() + "end"s + nlr(x)); + temp.push_back(indent() + "end"s + nl(x)); } break; } @@ -6410,7 +6453,7 @@ private: transformExp(newChainExp, temp, usage); if (isScoped) { popScope(); - temp.push_back(indent() + "end"s + nlr(x)); + temp.push_back(indent() + "end"s + nl(x)); } break; } @@ -6515,7 +6558,7 @@ private: assignment->action.set(assign); auto stmt = x->new_ptr(); stmt->content.set(assignment); - block->statements.push_back(stmt); + block->statementOrComments.push_back(stmt); } } ast_ptr nexp; @@ -6561,7 +6604,7 @@ private: expListAssign->expList.set(expList); auto stmt = x->new_ptr(); stmt->content.set(expListAssign); - block->statements.push_back(stmt); + block->statementOrComments.push_back(stmt); } switch (usage) { case ExpUsage::Common: @@ -6575,7 +6618,7 @@ private: default: break; } - if (block->statements.size() == 1) { + if (block->statementOrComments.size() == 1) { transformExp(nexp, out, usage, assignList); } else { auto body = x->new_ptr(); @@ -6668,8 +6711,8 @@ private: auto stmt2 = x->new_ptr(); stmt2->content.set(expListAssign); auto block = x->new_ptr(); - block->statements.push_back(stmt1); - block->statements.push_back(stmt2); + block->statementOrComments.push_back(stmt1); + block->statementOrComments.push_back(stmt2); auto body = x->new_ptr(); body->content.set(block); auto doNode = x->new_ptr(); @@ -6770,10 +6813,10 @@ private: } switch (usage) { case ExpUsage::Common: - out.push_back(indent() + join(temp) + nll(x)); + out.push_back(indent() + join(temp) + nl(x)); break; case ExpUsage::Return: - out.push_back(indent() + "return "s + join(temp) + nll(x)); + out.push_back(indent() + "return "s + join(temp) + nl(x)); break; case ExpUsage::Assignment: YUEE("invalid expression usage", x); break; default: @@ -7099,8 +7142,8 @@ private: throw CompileError("lua macro is not expanding to valid block\n"s + err, x); } if (!codes.empty()) { - codes.insert(0, indent() + "do"s + nll(chainValue)); - codes.append(_newLine + indent() + "end"s + nlr(chainValue)); + codes.insert(0, indent() + "do"s + nl(chainValue)); + codes.append(_newLine + indent() + "end"s + nl(chainValue)); } return {nullptr, nullptr, std::move(codes), std::move(localVars)}; } else { @@ -7189,7 +7232,7 @@ private: auto stmt = x->new_ptr(); stmt->content.set(exps); auto block = x->new_ptr(); - block->statements.push_back(stmt); + block->statementOrComments.push_back(stmt); info.node.set(block); } else { info.node.set(exp); @@ -7226,7 +7269,7 @@ private: return; } if (usage == ExpUsage::Common || (usage == ExpUsage::Return && node.is())) { - if (node.to()->statements.empty()) { + if (node.to()->statementOrComments.empty()) { out.push_back(Empty); } else { auto doBody = node->new_ptr(); @@ -7408,7 +7451,7 @@ private: auto assignment = assignmentFrom(toAst(checkVar, inExp), newExp(inExp, inExp), inExp); auto stmt = x->new_ptr(); stmt->content.set(assignment); - block->statements.push_back(stmt); + block->statementOrComments.push_back(stmt); } if (varName.empty()) { auto newUnaryExp = x->new_ptr(); @@ -7420,7 +7463,7 @@ private: auto assignment = assignmentFrom(assignExp, exp, x); auto stmt = x->new_ptr(); stmt->content.set(assignment); - block->statements.push_back(stmt); + block->statementOrComments.push_back(stmt); } auto findVar = getUnusedName("_find_"); auto itemVar = getUnusedName("_item_"); @@ -7436,7 +7479,7 @@ private: } auto blockStr = clearBuf(); auto checkBlock = toAst(blockStr, inExp); - block->statements.dup(checkBlock->statements); + block->statementOrComments.dup(checkBlock->statementOrComments); auto body = x->new_ptr(); body->content.set(block); auto doNode = x->new_ptr(); @@ -7456,16 +7499,16 @@ private: } else { auto arrayCheck = [&](bool exist) { auto indexVar = getUnusedName("_index_"); - _buf << indent() << "for "sv << indexVar << " = 1, #"sv << checkVar << " do"sv << nll(x); + _buf << indent() << "for "sv << indexVar << " = 1, #"sv << checkVar << " do"sv << nl(x); incIndentOffset(); - _buf << indent() << "if "sv << checkVar << '[' << indexVar << "] == "sv << varName << " then"sv << nll(x); + _buf << indent() << "if "sv << checkVar << '[' << indexVar << "] == "sv << varName << " then"sv << nl(x); incIndentOffset(); - _buf << indent() << "return "sv << (exist ? "true"sv : "false"sv) << nll(x); + _buf << indent() << "return "sv << (exist ? "true"sv : "false"sv) << nl(x); decIndentOffset(); - _buf << indent() << "end"sv << nll(x); + _buf << indent() << "end"sv << nl(x); decIndentOffset(); - _buf << indent() << "end"sv << nll(x); - _buf << indent() << "return "sv << (exist ? "false"sv : "true"sv) << nll(x); + _buf << indent() << "end"sv << nl(x); + _buf << indent() << "return "sv << (exist ? "false"sv : "true"sv) << nl(x); temp.push_back(clearBuf()); }; bool useShortCheck = (usage == ExpUsage::Closure) && !varName.empty() && !checkVar.empty() && isLocal(checkVar); @@ -7481,7 +7524,7 @@ private: pushAnonVarArg(); pushScope(); arrayCheck(true); - temp.push_front("(#"s + checkVar + " > 0 and "s + anonFuncStart() + nll(x)); + temp.push_front("(#"s + checkVar + " > 0 and "s + anonFuncStart() + nl(x)); popScope(); temp.push_back(indent() + anonFuncEnd() + ')'); if (unary_exp->inExp->not_) { @@ -7518,7 +7561,7 @@ private: arrayCheck(!unary_exp->inExp->not_); } else { arrayCheck(!unary_exp->inExp->not_); - temp.push_front(anonFuncStart() + nll(x)); + temp.push_front(anonFuncStart() + nl(x)); popScope(); temp.push_back(indent() + anonFuncEnd()); popAnonVarArg(); @@ -7558,7 +7601,7 @@ private: pushScope(); } else if (usage == ExpUsage::Assignment) { if (isScoped) { - temp.push_back(indent() + "do"s + nll(x)); + temp.push_back(indent() + "do"s + nl(x)); pushScope(); } } @@ -7598,10 +7641,10 @@ private: if (unary_exp->inExp->not_) { _buf << ")"sv; } - _buf << nll(x); + _buf << nl(x); temp.push_back(clearBuf()); if (usage == ExpUsage::Closure) { - temp.push_front(anonFuncStart() + nll(x)); + temp.push_front(anonFuncStart() + nl(x)); popScope(); temp.push_back(indent() + anonFuncEnd()); out.push_back(join(temp)); @@ -7610,7 +7653,7 @@ private: } else if (usage == ExpUsage::Assignment) { if (isScoped) { popScope(); - temp.push_back(indent() + "end"s + nll(x)); + temp.push_back(indent() + "end"s + nl(x)); } out.push_back(join(temp)); } else { @@ -7644,7 +7687,7 @@ private: } _buf << ')'; if (usage == ExpUsage::Assignment || usage == ExpUsage::Return) { - _buf << nll(discrete); + _buf << nl(discrete); } out.push_back(clearBuf()); } @@ -7764,7 +7807,7 @@ private: forceAddToScope(tableVar); auto it = values.begin(); if (ast_is(*it)) { - temp.push_back(indent() + "local "s + tableVar + " = { }"s + nll(x)); + temp.push_back(indent() + "local "s + tableVar + " = { }"s + nl(x)); } else { auto initialTab = x->new_ptr(); while (it != values.end() && !ast_is(*it)) { @@ -7772,7 +7815,7 @@ private: ++it; } transformTable(initialTab->values.objects(), temp); - temp.back() = indent() + "local "s + tableVar + " = "s + temp.back() + nll(*it); + temp.back() = indent() + "local "s + tableVar + " = "s + temp.back() + nl(*it); } for (; it != values.end(); ++it) { auto item = *it; @@ -7792,7 +7835,7 @@ private: transformAssignment(assignment, temp); } forceAddToScope(indexVar); - temp.push_back(indent() + "local "s + indexVar + " = 1"s + nll(item)); + temp.push_back(indent() + "local "s + indexVar + " = 1"s + nl(item)); _buf << "for "sv << keyVar << ',' << valueVar << " in pairs "sv << objVar << "\n\tif "sv << indexVar << "=="sv << keyVar << "\n\t\t"sv << tableVar << "[]="sv << valueVar @@ -7816,7 +7859,7 @@ private: transformAssignment(assignment, temp); } forceAddToScope(indexVar); - temp.push_back(indent() + "local "s + indexVar + " = #"s + tableVar + " + 1"s + nll(item)); + temp.push_back(indent() + "local "s + indexVar + " = #"s + tableVar + " + 1"s + nl(item)); _buf << "for "sv << valueVar << " in *"sv << objVar << "\n\t"sv << tableVar << '[' << indexVar << "]="sv << valueVar << "\n\t"sv << indexVar << "+=1"sv; @@ -7999,9 +8042,9 @@ private: break; case ExpUsage::Closure: { out.push_back(join(temp)); - out.back().append(indent() + "return "s + tableVar + nlr(x)); + out.back().append(indent() + "return "s + tableVar + nl(x)); popScope(); - out.back().insert(0, anonFuncStart() + nll(x)); + out.back().insert(0, anonFuncStart() + nl(x)); out.back().append(indent() + anonFuncEnd()); popAnonVarArg(); popFunctionScope(); @@ -8017,13 +8060,13 @@ private: if (extraScope) popScope(); out.push_back(join(temp)); if (extraScope) { - out.back() = indent() + "do"s + nll(x) + out.back() + indent() + "end"s + nlr(x); + out.back() = indent() + "do"s + nl(x) + out.back() + indent() + "end"s + nl(x); } break; } case ExpUsage::Return: out.push_back(join(temp)); - out.back().append(indent() + "return "s + tableVar + nlr(x)); + out.back().append(indent() + "return "s + tableVar + nl(x)); break; default: break; @@ -8144,11 +8187,11 @@ private: default: YUEE("AST node mismatch", item); break; } if (!isMetamethod) { - temp.back() = indent() + (value == values.back() ? temp.back() : temp.back() + ',') + nll(value); + temp.back() = indent() + (value == values.back() ? temp.back() : temp.back() + ',') + nl(value); } } if (metatable->pairs.empty() && !metatableItem) { - out.push_back('{' + nll(x) + join(temp)); + out.push_back('{' + nl(x) + join(temp)); decIndentOffset(); out.back() += (indent() + '}'); } else { @@ -8158,7 +8201,7 @@ private: decIndentOffset(); tabStr += "{ }"sv; } else { - tabStr += ('{' + nll(x) + join(temp)); + tabStr += ('{' + nl(x) + join(temp)); decIndentOffset(); tabStr += (indent() + '}'); } @@ -8213,7 +8256,7 @@ private: break; case id(): transformExp(static_cast(item), temp, ExpUsage::Closure); - temp.back() = indent() + "if "s + temp.back() + " then"s + nll(item); + temp.back() = indent() + "if "s + temp.back() + " then"s + nl(item); pushScope(); break; default: YUEE("AST node mismatch", item); break; @@ -8235,7 +8278,7 @@ private: _buf << join(temp) << value; for (size_t i = 0; i < compInner->items.objects().size(); ++i) { popScope(); - _buf << indent() << "end"sv << nll(comp); + _buf << indent() << "end"sv << nl(comp); } out.push_back(clearBuf()); } @@ -8333,7 +8376,7 @@ private: break; case id(): transformExp(static_cast(item), temp, ExpUsage::Closure); - temp.back() = indent() + "if "s + temp.back() + " then"s + nll(item); + temp.back() = indent() + "if "s + temp.back() + " then"s + nl(item); pushScope(); break; default: YUEE("AST node mismatch", item); break; @@ -8353,27 +8396,27 @@ private: for (size_t i = 0; i < compInner->items.objects().size(); ++i) { popScope(); } - _buf << indent() << "local "sv << accumVar << " = { }"sv << nll(comp); + _buf << indent() << "local "sv << accumVar << " = { }"sv << nl(comp); if (isSpread) { _buf << join(temp); _buf << assignStr; } else { - _buf << indent() << "local "sv << lenVar << " = 1"sv << nll(comp); + _buf << indent() << "local "sv << lenVar << " = 1"sv << nl(comp); _buf << join(temp); _buf << assignStr; - _buf << indent(int(temp.size())) << lenVar << " = "sv << lenVar << " + 1"sv << nll(comp); + _buf << indent(int(temp.size())) << lenVar << " = "sv << lenVar << " + 1"sv << nl(comp); } for (int ind = int(temp.size()) - 1; ind > -1; --ind) { - _buf << indent(ind) << "end"sv << nll(comp); + _buf << indent(ind) << "end"sv << nl(comp); } switch (usage) { case ExpUsage::Common: break; case ExpUsage::Closure: { out.push_back(clearBuf()); - out.back().append(indent() + "return "s + accumVar + nlr(comp)); + out.back().append(indent() + "return "s + accumVar + nl(comp)); popScope(); - out.back().insert(0, anonFuncStart() + nll(comp)); + out.back().insert(0, anonFuncStart() + nl(comp)); out.back().append(indent() + anonFuncEnd()); popAnonVarArg(); popFunctionScope(); @@ -8390,13 +8433,13 @@ private: out.back().append(temp.back()); if (extraScope) { popScope(); - out.back() = indent() + "do"s + nll(comp) + out.back() + indent() + "end"s + nlr(comp); + out.back() = indent() + "do"s + nl(comp) + out.back() + indent() + "end"s + nl(comp); } break; } case ExpUsage::Return: out.push_back(clearBuf()); - out.back().append(indent() + "return "s + accumVar + nlr(comp)); + out.back().append(indent() + "return "s + accumVar + nl(comp)); break; default: break; @@ -8512,13 +8555,13 @@ private: std::string prefix; if (!inClosure && needScope) { extraScope = true; - prefix = indent() + "do"s + nll(x); + prefix = indent() + "do"s + nl(x); pushScope(); } listVar = getUnusedName("_list_"sv); varBefore.push_back(listVar); transformChainValue(chain, temp, ExpUsage::Closure); - _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); + _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nl(nameList); } if (startValue.empty()) { startValue = "1"s; @@ -8529,15 +8572,15 @@ private: std::string prefix; if (!extraScope && !inClosure && needScope) { extraScope = true; - prefix = indent() + "do"s + nll(x); + prefix = indent() + "do"s + nl(x); pushScope(); } minVar = getUnusedName("_min_"sv); varBefore.push_back(minVar); if (startStatus == NumState::Negtive) { - _buf << prefix << indent() << "local "sv << minVar << " = "sv << "#"sv << listVar << " + "sv << startValue << " + 1"sv << nll(nameList); + _buf << prefix << indent() << "local "sv << minVar << " = "sv << "#"sv << listVar << " + "sv << startValue << " + 1"sv << nl(nameList); } else { - _buf << prefix << indent() << "local "sv << minVar << " = "sv << startValue << nll(nameList); + _buf << prefix << indent() << "local "sv << minVar << " = "sv << startValue << nl(nameList); } } bool defaultStop = false; @@ -8550,22 +8593,22 @@ private: std::string prefix; if (!extraScope && !inClosure && needScope) { extraScope = true; - prefix = indent() + "do"s + nll(x); + prefix = indent() + "do"s + nl(x); pushScope(); } maxVar = getUnusedName("_max_"sv); varBefore.push_back(maxVar); if (stopStatus == NumState::Negtive) { - _buf << indent() << "local "sv << maxVar << " = "sv << "#"sv << listVar << " + "sv << stopValue << " + 1"sv << nll(nameList); + _buf << indent() << "local "sv << maxVar << " = "sv << "#"sv << listVar << " + "sv << stopValue << " + 1"sv << nl(nameList); } else { - _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList); + _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nl(nameList); } } if (startStatus == NumState::Unknown) { - _buf << indent() << minVar << " = "sv << minVar << " < 0 and #"sv << listVar << " + "sv << minVar << " + 1 or "sv << minVar << nll(nameList); + _buf << indent() << minVar << " = "sv << minVar << " < 0 and #"sv << listVar << " + "sv << minVar << " + 1 or "sv << minVar << nl(nameList); } if (!defaultStop && stopStatus == NumState::Unknown) { - _buf << indent() << maxVar << " = "sv << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " + 1 or "sv << maxVar << nll(nameList); + _buf << indent() << maxVar << " = "sv << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " + 1 or "sv << maxVar << nl(nameList); } _buf << indent() << "for "sv << indexVar << " = "sv; if (startValue.empty()) { @@ -8598,8 +8641,8 @@ private: if (!stepValue.empty()) { _buf << ", "sv << stepValue; } - _buf << " do"sv << nlr(loopTarget); - _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList); + _buf << " do"sv << nl(loopTarget); + _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nl(nameList); out.push_back(clearBuf()); BLOCK_END bool newListVal = false; @@ -8610,21 +8653,21 @@ private: } if (!endWithSlice) { transformExp(star_exp->value, temp, ExpUsage::Closure); - if (newListVal) _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); - _buf << indent() << "for "sv << indexVar << " = 1, #"sv << listVar << " do"sv << nlr(loopTarget); - _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList); + if (newListVal) _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nl(nameList); + _buf << indent() << "for "sv << indexVar << " = 1, #"sv << listVar << " do"sv << nl(loopTarget); + _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nl(nameList); out.push_back(clearBuf()); } break; } case id(): transformExp(static_cast(loopTarget), temp, ExpUsage::Closure); - _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget); + _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nl(loopTarget); out.push_back(clearBuf()); break; case id(): transformExpList(static_cast(loopTarget), temp); - _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget); + _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nl(loopTarget); out.push_back(clearBuf()); break; default: YUEE("AST node mismatch", loopTarget); break; @@ -8722,7 +8765,7 @@ private: const auto& start = *it; const auto& stop = *(++it); const auto& step = *(++it); - _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : ", "s + step) << " do"sv << nll(var); + _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : ", "s + step) << " do"sv << nl(var); pushScope(); forceAddToScope(varName); markVarLocalConst(varName); @@ -8740,7 +8783,7 @@ private: break; case id(): { auto newBlock = bodyOrStmt->new_ptr(); - newBlock->statements.push_back(bodyOrStmt); + newBlock->statementOrComments.push_back(bodyOrStmt); transformBlock(newBlock, out, usage, assignList); break; } @@ -8837,9 +8880,9 @@ private: } void addDoToLastLineReturn(ast_node* body) { - if (auto block = ast_cast(body); block && !block->statements.empty()) { - auto last = static_cast(block->statements.back()); - if (last->content.is()) { + if (auto block = ast_cast(body); block && !block->statementOrComments.empty()) { + auto last = lastStatementFrom(block); + if (last && last->content.is()) { auto doNode = last->new_ptr(); auto newBody = last->new_ptr(); auto newStmt = last->new_ptr(); @@ -8866,8 +8909,8 @@ private: if (withContinue) { if (target < 502) { if (auto block = ast_cast(body)) { - if (!block->statements.empty()) { - auto stmt = static_cast(block->statements.back()); + if (!block->statementOrComments.empty()) { + auto stmt = lastStatementFrom(block); if (auto breakLoop = ast_cast(stmt->content)) { extraDo = breakLoop->type.is(); } @@ -8876,11 +8919,11 @@ private: auto continueVar = getUnusedName("_continue_"sv); addToScope(continueVar); _continueVars.push({continueVar, nullptr}); - _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); - _buf << indent() << "repeat"sv << nll(body); + _buf << indent() << "local "sv << continueVar << " = false"sv << nl(body); + _buf << indent() << "repeat"sv << nl(body); pushScope(); if (extraDo) { - _buf << indent() << "do"sv << nll(body); + _buf << indent() << "do"sv << nl(body); pushScope(); } temp.push_back(clearBuf()); @@ -8900,14 +8943,14 @@ private: if (target < 502) { if (extraDo) { popScope(); - _buf << indent() << "end"sv << nll(body); + _buf << indent() << "end"sv << nl(body); } - _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); + _buf << indent() << _continueVars.top().var << " = true"sv << nl(body); popScope(); - _buf << indent() << "until true"sv << nlr(body); - _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); - _buf << indent(1) << "break"sv << nlr(body); - _buf << indent() << "end"sv << nlr(body); + _buf << indent() << "until true"sv << nl(body); + _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nl(body); + _buf << indent(1) << "break"sv << nl(body); + _buf << indent() << "end"sv << nl(body); temp.push_back(clearBuf()); _continueVars.pop(); } else { @@ -8931,8 +8974,8 @@ private: if (withContinue) { if (target < 502) { if (auto block = ast_cast(body)) { - if (!block->statements.empty()) { - auto stmt = static_cast(block->statements.back()); + if (!block->statementOrComments.empty()) { + auto stmt = lastStatementFrom(block); if (auto breakLoop = ast_cast(stmt->content)) { extraDo = breakLoop->type.is(); } @@ -8949,12 +8992,12 @@ private: assign->values.push_back(repeatNode->condition); _continueVars.push({continueVar, assignment.get()}); } - _buf << indent() << "local "sv << conditionVar << " = false"sv << nll(body); - _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); - _buf << indent() << "repeat"sv << nll(body); + _buf << indent() << "local "sv << conditionVar << " = false"sv << nl(body); + _buf << indent() << "local "sv << continueVar << " = false"sv << nl(body); + _buf << indent() << "repeat"sv << nl(body); pushScope(); if (extraDo) { - _buf << indent() << "do"sv << nll(body); + _buf << indent() << "do"sv << nl(body); pushScope(); } temp.push_back(clearBuf()); @@ -8975,14 +9018,14 @@ private: transformAssignment(_continueVars.top().condAssign, temp); if (extraDo) { popScope(); - _buf << indent() << "end"sv << nll(body); + _buf << indent() << "end"sv << nl(body); } - _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); + _buf << indent() << _continueVars.top().var << " = true"sv << nl(body); popScope(); - _buf << indent() << "until true"sv << nlr(body); - _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); - _buf << indent(1) << "break"sv << nlr(body); - _buf << indent() << "end"sv << nlr(body); + _buf << indent() << "until true"sv << nl(body); + _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nl(body); + _buf << indent(1) << "break"sv << nl(body); + _buf << indent() << "end"sv << nl(body); temp.push_back(clearBuf()); _continueVars.pop(); } else { @@ -9000,7 +9043,7 @@ private: auto breakLoopType = getBreakLoopType(forNode->body, Empty); transformLoopBody(forNode->body, temp, breakLoopType, ExpUsage::Common); popScope(); - out.push_back(join(temp) + indent() + "end"s + nlr(forNode)); + out.push_back(join(temp) + indent() + "end"s + nl(forNode)); } std::string transformForInner(For_t* forNode, str_list& out) { @@ -9010,9 +9053,9 @@ private: std::string len = getUnusedName("_len_"sv); addToScope(len); auto breakLoopType = getBreakLoopType(forNode->body, accum); - _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(forNode); + _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(forNode); out.emplace_back(clearBuf()); - _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode); + _buf << indent() << "local "sv << len << " = 1"sv << nl(forNode); auto& lenAssign = out.emplace_back(clearBuf()); transformForHead(forNode, out); if (hasBreakWithValue(breakLoopType)) { @@ -9028,7 +9071,7 @@ private: } } popScope(); - out.push_back(indent() + "end"s + nlr(forNode)); + out.push_back(indent() + "end"s + nl(forNode)); return accum; } @@ -9044,9 +9087,9 @@ private: std::string& funcStart = temp.emplace_back(); pushScope(); auto accum = transformForInner(forNode, temp); - temp.push_back(indent() + "return "s + accum + nlr(forNode)); + temp.push_back(indent() + "return "s + accum + nl(forNode)); popScope(); - funcStart = anonFuncStart() + nll(forNode); + funcStart = anonFuncStart() + nl(forNode); temp.push_back(indent() + anonFuncEnd()); popAnonVarArg(); popFunctionScope(); @@ -9059,7 +9102,7 @@ private: bool isScoped = !currentScope().lastStatement; if (assignExpList) { if (isScoped) { - _buf << indent() << "do"sv << nll(forNode); + _buf << indent() << "do"sv << nl(forNode); pushScope(); } auto accum = transformForInner(forNode, temp); @@ -9071,7 +9114,7 @@ private: transformAssignment(assignment, temp); if (isScoped) { popScope(); - temp.push_back(indent() + "end"s + nlr(forNode)); + temp.push_back(indent() + "end"s + nl(forNode)); } } else { auto accum = transformForInner(forNode, temp); @@ -9108,10 +9151,10 @@ private: auto breakLoopType = getBreakLoopType(forEach->body, Empty); transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common); popScope(); - out.push_back(temp.front() + temp.back() + indent() + "end"s + nlr(forEach)); + out.push_back(temp.front() + temp.back() + indent() + "end"s + nl(forEach)); if (extraScoped) { popScope(); - out.back().append(indent() + "end"s + nlr(forEach)); + out.back().append(indent() + "end"s + nl(forEach)); } } @@ -9122,9 +9165,9 @@ private: std::string len = getUnusedName("_len_"sv); addToScope(len); auto breakLoopType = getBreakLoopType(forEach->body, accum); - _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(forEach); + _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(forEach); out.emplace_back(clearBuf()); - _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach); + _buf << indent() << "local "sv << len << " = 1"sv << nl(forEach); auto& lenAssign = out.emplace_back(clearBuf()); transformForEachHead(forEach->nameList, forEach->loopValue, out, true); if (hasBreakWithValue(breakLoopType)) { @@ -9140,7 +9183,7 @@ private: } } popScope(); - out.push_back(indent() + "end"s + nlr(forEach)); + out.push_back(indent() + "end"s + nl(forEach)); return accum; } @@ -9156,9 +9199,9 @@ private: std::string& funcStart = temp.emplace_back(); pushScope(); auto accum = transformForEachInner(forEach, temp); - temp.push_back(indent() + "return "s + accum + nlr(forEach)); + temp.push_back(indent() + "return "s + accum + nl(forEach)); popScope(); - funcStart = anonFuncStart() + nll(forEach); + funcStart = anonFuncStart() + nl(forEach); temp.push_back(indent() + anonFuncEnd()); popAnonVarArg(); popFunctionScope(); @@ -9171,7 +9214,7 @@ private: bool isScoped = !currentScope().lastStatement; if (assignExpList) { if (isScoped) { - _buf << indent() << "do"sv << nll(forEach); + _buf << indent() << "do"sv << nl(forEach); pushScope(); } auto accum = transformForEachInner(forEach, temp); @@ -9183,7 +9226,7 @@ private: transformAssignment(assignment, temp); if (isScoped) { popScope(); - temp.push_back(indent() + "end"s + nlr(forEach)); + temp.push_back(indent() + "end"s + nl(forEach)); } } else { auto accum = transformForEachInner(forEach, temp); @@ -9410,7 +9453,7 @@ private: pushScope(); transformClassDecl(classDecl, temp, ExpUsage::Return); popScope(); - funcStart = anonFuncStart() + nll(classDecl); + funcStart = anonFuncStart() + nl(classDecl); temp.push_back(indent() + anonFuncEnd()); popAnonVarArg(); popFunctionScope(); @@ -9434,7 +9477,7 @@ private: bool newDefined = false; std::tie(className, newDefined, classTextName) = defineClassVariable(assignable); if (newDefined) { - temp.push_back(indent() + "local "s + className + nll(classDecl)); + temp.push_back(indent() + "local "s + className + nl(classDecl)); } if (classTextName.empty()) { if (auto chain = ast_cast(assignable->item)) { @@ -9471,12 +9514,12 @@ private: } } if (isScoped) { - temp.push_back(indent() + "do"s + nll(classDecl)); + temp.push_back(indent() + "do"s + nl(classDecl)); pushScope(); } auto classVar = getUnusedName("_class_"sv); addToScope(classVar); - temp.push_back(indent() + "local "s + classVar + nll(classDecl)); + temp.push_back(indent() + "local "s + classVar + nl(classDecl)); auto block = classDecl->new_ptr(); str_list classConstVars; if (body) { @@ -9485,7 +9528,7 @@ private: if (auto statement = ast_cast(item)) { ClassDecl_t* clsDecl = nullptr; if (auto assignment = assignmentFrom(statement)) { - block->statements.push_back(statement); + block->statementOrComments.push_back(statement); auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark); for (const auto& name : names) { varDefs.push_back(name.first); @@ -9515,12 +9558,12 @@ private: clsDecl = value->get_by_path(); BLOCK_END } else if (auto expList = expListFrom(statement)) { - block->statements.push_back(statement); + block->statementOrComments.push_back(statement); if (auto value = singleValueFrom(expList)) { clsDecl = value->get_by_path(); } } else if (auto local = statement->content.as()) { - block->statements.push_back(statement); + block->statementOrComments.push_back(statement); if (auto values = local->item.as()) { for (auto name : values->nameList->names.objects()) { auto varName = variableToString(static_cast(name)); @@ -9583,7 +9626,6 @@ private: } } auto stmt = statement->new_ptr(); - stmt->comments.dup(statement->comments); auto newAttrib = localAttrib->new_ptr(); newAttrib->attrib.set(localAttrib->attrib); newAttrib->leftList.dup(localAttrib->leftList); @@ -9591,7 +9633,7 @@ private: newAttrib->forceLocal = false; stmt->content.set(newAttrib); stmt->appendix.set(statement->appendix); - block->statements.push_back(stmt); + block->statementOrComments.push_back(stmt); } else if (statement->content.is()) { throw CompileError("global statement is not allowed here"sv, statement->content); } @@ -9605,7 +9647,7 @@ private: } } if (!varDefs.empty()) { - temp.push_back(indent() + "local "s + join(varDefs, ", "sv) + nll(body)); + temp.push_back(indent() + "local "s + join(varDefs, ", "sv) + nl(body)); } } std::string parent, parentVar; @@ -9615,7 +9657,7 @@ private: transformExp(extend, temp, ExpUsage::Closure); parent = std::move(temp.back()); temp.pop_back(); - temp.push_back(indent() + "local "s + parentVar + " = "s + parent + nll(classDecl)); + temp.push_back(indent() + "local "s + parentVar + " = "s + parent + nl(classDecl)); } auto baseVar = getUnusedName("_base_"sv); addToScope(baseVar); @@ -9634,7 +9676,7 @@ private: for (; it != members.end(); ++it) { auto& member = *it; if (member.type == MemType::Property) { - statements.push_back(indent() + member.item + nll(content)); + statements.push_back(indent() + member.item + nl(content)); } else { member.item = indent(1) + member.item; } @@ -9646,32 +9688,34 @@ private: } } for (const auto& classVar : classConstVars) { - auto& scope = _scopes.back(); - scope.vars->insert_or_assign(classVar, VarType::Local); + forceAddToScope(classVar); } - for (auto stmt_ : block->statements.objects()) { - transformStatement(static_cast(stmt_), statements); + forceAddToScope("self"s); + for (auto stmt_ : block->statementOrComments.objects()) { + if (auto stmt = ast_cast(stmt_)) { + transformStatement(stmt, statements); + } } for (auto& member : members) { switch (member.type) { case MemType::Common: - commons.push_back((commons.empty() ? Empty : ',' + nll(member.node)) + member.item); + commons.push_back((commons.empty() ? Empty : ',' + nl(member.node)) + member.item); break; case MemType::Builtin: - builtins.push_back((builtins.empty() ? Empty : ',' + nll(member.node)) + member.item); + builtins.push_back((builtins.empty() ? Empty : ',' + nl(member.node)) + member.item); break; default: break; } } if (!commons.empty()) { - temp.back() += '{' + nll(body); - temp.push_back(join(commons) + nll(body)); - temp.push_back(indent() + '}' + nll(body)); + temp.back() += '{' + nl(body); + temp.push_back(join(commons) + nl(body)); + temp.push_back(indent() + '}' + nl(body)); } else { - temp.back() += "{ }"s + nll(body); + temp.back() += "{ }"s + nl(body); } } else { - temp.back() += "{ }"s + nll(classDecl); + temp.back() += "{ }"s + nl(classDecl); } if (classDecl->mixes) { auto item = getUnusedName("_item_"sv); @@ -9704,72 +9748,72 @@ private: transformAssignment(assignment, tmp); } if (extend) { - _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nll(classDecl); + _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nl(classDecl); } - _buf << indent() << classVar << " = "sv << globalVar("setmetatable"sv, classDecl, AccessType::Read) << "({"sv << nll(classDecl); + _buf << indent() << classVar << " = "sv << globalVar("setmetatable"sv, classDecl, AccessType::Read) << "({"sv << nl(classDecl); if (!builtins.empty()) { - _buf << join(builtins) << ',' << nll(classDecl); + _buf << join(builtins) << ',' << nl(classDecl); } else { if (extend) { - _buf << indent(1) << "__init = function(self, ...)"sv << nll(classDecl); - _buf << indent(2) << "return "sv << classVar << ".__parent.__init(self, ...)"sv << nll(classDecl); - _buf << indent(1) << "end,"sv << nll(classDecl); + _buf << indent(1) << "__init = function(self, ...)"sv << nl(classDecl); + _buf << indent(2) << "return "sv << classVar << ".__parent.__init(self, ...)"sv << nl(classDecl); + _buf << indent(1) << "end,"sv << nl(classDecl); } else { - _buf << indent(1) << "__init = function() end,"sv << nll(classDecl); + _buf << indent(1) << "__init = function() end,"sv << nl(classDecl); } } _buf << indent(1) << "__base = "sv << baseVar; if (!classTextName.empty()) { - _buf << ","sv << nll(classDecl); + _buf << ","sv << nl(classDecl); _buf << indent(1) << "__name = "sv << classTextName; } if (extend) { - _buf << ","sv << nll(classDecl); + _buf << ","sv << nl(classDecl); _buf << indent(1) << "__parent = "sv << parentVar; } - _buf << nll(classDecl); - _buf << indent() << "}, {"sv << nll(classDecl); + _buf << nl(classDecl); + _buf << indent() << "}, {"sv << nl(classDecl); if (extend) { - _buf << indent(1) << "__index = function(cls, name)"sv << nll(classDecl); - _buf << indent(2) << "local val = rawget("sv << baseVar << ", name)"sv << nll(classDecl); - _buf << indent(2) << "if val == nil then"sv << nll(classDecl); - _buf << indent(3) << "local parent = rawget(cls, \"__parent\")"sv << nll(classDecl); - _buf << indent(3) << "if parent then"sv << nll(classDecl); - _buf << indent(4) << "return parent[name]"sv << nll(classDecl); - _buf << indent(3) << "end"sv << nll(classDecl); - _buf << indent(2) << "else"sv << nll(classDecl); - _buf << indent(3) << "return val"sv << nll(classDecl); - _buf << indent(2) << "end"sv << nll(classDecl); - _buf << indent(1) << "end,"sv << nll(classDecl); + _buf << indent(1) << "__index = function(cls, name)"sv << nl(classDecl); + _buf << indent(2) << "local val = rawget("sv << baseVar << ", name)"sv << nl(classDecl); + _buf << indent(2) << "if val == nil then"sv << nl(classDecl); + _buf << indent(3) << "local parent = rawget(cls, \"__parent\")"sv << nl(classDecl); + _buf << indent(3) << "if parent then"sv << nl(classDecl); + _buf << indent(4) << "return parent[name]"sv << nl(classDecl); + _buf << indent(3) << "end"sv << nl(classDecl); + _buf << indent(2) << "else"sv << nl(classDecl); + _buf << indent(3) << "return val"sv << nl(classDecl); + _buf << indent(2) << "end"sv << nl(classDecl); + _buf << indent(1) << "end,"sv << nl(classDecl); } else { - _buf << indent(1) << "__index = "sv << baseVar << ","sv << nll(classDecl); + _buf << indent(1) << "__index = "sv << baseVar << ","sv << nl(classDecl); } - _buf << indent(1) << "__call = function(cls, ...)"sv << nll(classDecl); + _buf << indent(1) << "__call = function(cls, ...)"sv << nl(classDecl); pushScope(); auto selfVar = getUnusedName("_self_"sv); addToScope(selfVar); - _buf << indent(1) << "local "sv << selfVar << " = setmetatable({ }, "sv << baseVar << ")"sv << nll(classDecl); - _buf << indent(1) << "cls.__init("sv << selfVar << ", ...)"sv << nll(classDecl); - _buf << indent(1) << "return "sv << selfVar << nll(classDecl); + _buf << indent(1) << "local "sv << selfVar << " = setmetatable({ }, "sv << baseVar << ")"sv << nl(classDecl); + _buf << indent(1) << "cls.__init("sv << selfVar << ", ...)"sv << nl(classDecl); + _buf << indent(1) << "return "sv << selfVar << nl(classDecl); popScope(); - _buf << indent(1) << "end"sv << nll(classDecl); - _buf << indent() << "})"sv << nll(classDecl); - _buf << indent() << baseVar << ".__class = "sv << classVar << nll(classDecl); + _buf << indent(1) << "end"sv << nl(classDecl); + _buf << indent() << "})"sv << nl(classDecl); + _buf << indent() << baseVar << ".__class = "sv << classVar << nl(classDecl); if (!statements.empty()) { - _buf << indent() << "local self = "sv << classVar << ';' << nll(classDecl); + _buf << indent() << "local self = "sv << classVar << ';' << nl(classDecl); } _buf << join(statements); if (extend) { - _buf << indent() << "if "sv << parentVar << ".__inherited then"sv << nll(classDecl); - _buf << indent(1) << parentVar << ".__inherited("sv << parentVar << ", "sv << classVar << ")"sv << nll(classDecl); - _buf << indent() << "end"sv << nll(classDecl); + _buf << indent() << "if "sv << parentVar << ".__inherited then"sv << nl(classDecl); + _buf << indent(1) << parentVar << ".__inherited("sv << parentVar << ", "sv << classVar << ")"sv << nl(classDecl); + _buf << indent() << "end"sv << nl(classDecl); } if (!assignItem.empty()) { - _buf << indent() << assignItem << " = "sv << classVar << nll(classDecl); + _buf << indent() << assignItem << " = "sv << classVar << nl(classDecl); } switch (usage) { case ExpUsage::Return: { - _buf << indent() << "return "sv << classVar << nlr(classDecl); + _buf << indent() << "return "sv << classVar << nl(classDecl); break; } case ExpUsage::Assignment: { @@ -9781,7 +9825,7 @@ private: temp.push_back(clearBuf()); if (isScoped) { popScope(); - temp.push_back(indent() + "end"s + nlr(classDecl)); + temp.push_back(indent() + "end"s + nl(classDecl)); } out.push_back(join(temp)); } @@ -9944,7 +9988,7 @@ private: pushScope(); transformWith(with, temp, nullptr, true); popScope(); - funcStart = anonFuncStart() + nll(with); + funcStart = anonFuncStart() + nl(with); temp.push_back(indent() + anonFuncEnd()); popAnonVarArg(); popFunctionScope(); @@ -9975,7 +10019,7 @@ private: assignment->action.set(assign); if (needScope) { extraScope = true; - temp.push_back(indent() + "do"s + nll(with)); + temp.push_back(indent() + "do"s + nl(with)); pushScope(); } transformAssignment(assignment, temp); @@ -10001,7 +10045,7 @@ private: assignment->action.set(with->assign); if (needScope) { extraScope = true; - temp.push_back(indent() + "do"s + nll(with)); + temp.push_back(indent() + "do"s + nl(with)); pushScope(); } transformAssignment(assignment, temp); @@ -10017,7 +10061,7 @@ private: assignment->action.set(assign); if (needScope) { extraScope = true; - temp.push_back(indent() + "do"s + nll(with)); + temp.push_back(indent() + "do"s + nl(with)); pushScope(); } transformAssignment(assignment, temp); @@ -10071,7 +10115,7 @@ private: }); popScope(); if (extraScope) { - temp.push_back(indent() + "do"s + nll(with)); + temp.push_back(indent() + "do"s + nl(with)); pushScope(); } } @@ -10102,7 +10146,7 @@ private: stmt->content.set(expListAssign); auto repeatNode = toAst("repeat\n\t--\nuntil true"s, x); auto block = x->new_ptr(); - block->statements.push_back(stmt); + block->statementOrComments.push_back(stmt); repeatNode->body.set(block); auto sVal = x->new_ptr(); sVal->value.set(repeatNode); @@ -10115,10 +10159,10 @@ private: auto repeatNode = toAst("repeat\n\t--\nuntil true"s, x); auto block = x->new_ptr(); if (auto blk = with->body.as()) { - block->statements.dup(blk->statements); + block->statementOrComments.dup(blk->statementOrComments); } else { auto stmt = with->body.to(); - block->statements.push_back(stmt); + block->statementOrComments.push_back(stmt); } repeatNode->body.set(block); auto sVal = x->new_ptr(); @@ -10128,12 +10172,12 @@ private: transformed = true; } else if (!extraScope && assignList) { if (auto block = with->body.as()) { - if (!block->statements.empty()) { - Statement_t* stmt = static_cast(block->statements.back()); - if (stmt->content.is()) { + if (!block->statementOrComments.empty()) { + Statement_t* stmt = lastStatementFrom(block); + if (stmt && stmt->content.is()) { auto newBlock = with->body->new_ptr(); - newBlock->statements.dup(block->statements); - newBlock->statements.pop_back(); + newBlock->statementOrComments.dup(block->statementOrComments); + newBlock->statementOrComments.pop_back(); transform_plain_body(newBlock, temp, ExpUsage::Common); auto newBody = stmt->new_ptr(); newBody->content.set(stmt); @@ -10171,12 +10215,12 @@ private: if (returnValue) { auto last = lastStatementFrom(with->body); if (last && !last->content.is()) { - temp.push_back(indent() + "return "s + withVar + nll(with)); + temp.push_back(indent() + "return "s + withVar + nl(with)); } } if (extraScope) { popScope(); - temp.push_back(indent() + "end"s + nll(with)); + temp.push_back(indent() + "end"s + nl(with)); } out.push_back(join(temp)); } @@ -10386,7 +10430,7 @@ private: } } if (_info.exportDefault) { - out.back().append(indent() + _info.moduleName + " = "s + names.back().first + nlr(exportNode)); + out.back().append(indent() + _info.moduleName + " = "s + names.back().first + nl(exportNode)); } else { str_list lefts, rights; for (const auto& name : names) { @@ -10399,7 +10443,7 @@ private: lefts.push_back(_info.moduleName + "[\""s + realName + "\"]"s); rights.push_back(name.first); } - out.back().append(indent() + join(lefts, ", "sv) + " = "s + join(rights, ", "sv) + nlr(exportNode)); + out.back().append(indent() + join(lefts, ", "sv) + " = "s + join(rights, ", "sv) + nl(exportNode)); } } } else { @@ -10488,7 +10532,7 @@ private: break; case id(): transformExp(static_cast(item), temp, ExpUsage::Closure); - temp.back() = indent() + "if "s + temp.back() + " then"s + nll(item); + temp.back() = indent() + "if "s + temp.back() + " then"s + nl(item); pushScope(); break; default: YUEE("AST node mismatch", item); break; @@ -10501,27 +10545,27 @@ private: for (size_t i = 0; i < compInner->items.objects().size(); ++i) { popScope(); } - _buf << indent() << "local "sv << tbl << " = { }"sv << nll(comp); + _buf << indent() << "local "sv << tbl << " = { }"sv << nl(comp); _buf << join(temp); pushScope(); if (!comp->value) { auto keyVar = getUnusedName("_key_"sv); auto valVar = getUnusedName("_val_"sv); - _buf << indent(int(temp.size()) - 1) << "local "sv << keyVar << ", "sv << valVar << " = "sv << kv.front() << nll(comp); + _buf << indent(int(temp.size()) - 1) << "local "sv << keyVar << ", "sv << valVar << " = "sv << kv.front() << nl(comp); kv.front() = keyVar; kv.push_back(valVar); } - _buf << indent(int(temp.size()) - 1) << tbl << "["sv << kv.front() << "] = "sv << kv.back() << nll(comp); + _buf << indent(int(temp.size()) - 1) << tbl << "["sv << kv.front() << "] = "sv << kv.back() << nl(comp); for (int ind = int(temp.size()) - 2; ind > -1; --ind) { - _buf << indent(ind) << "end"sv << nll(comp); + _buf << indent(ind) << "end"sv << nl(comp); } popScope(); - _buf << indent() << "end"sv << nll(comp); + _buf << indent() << "end"sv << nl(comp); switch (usage) { case ExpUsage::Closure: - out.push_back(clearBuf() + indent() + "return "s + tbl + nlr(comp)); + out.push_back(clearBuf() + indent() + "return "s + tbl + nl(comp)); popScope(); - out.back().insert(0, anonFuncStart() + nll(comp)); + out.back().insert(0, anonFuncStart() + nl(comp)); out.back().append(indent() + anonFuncEnd()); popAnonVarArg(); popFunctionScope(); @@ -10537,13 +10581,13 @@ private: out.back().append(temp.back()); if (extraScope) { popScope(); - out.back().insert(0, indent() + "do"s + nll(comp)); - out.back().append(indent() + "end"s + nlr(comp)); + out.back().insert(0, indent() + "do"s + nl(comp)); + out.back().append(indent() + "end"s + nl(comp)); } break; } case ExpUsage::Return: - out.push_back(clearBuf() + indent() + "return "s + tbl + nlr(comp)); + out.push_back(clearBuf() + indent() + "return "s + tbl + nl(comp)); break; default: break; @@ -10581,19 +10625,19 @@ private: funcStart = &temp.emplace_back(); pushScope(); } else { - temp.push_back(indent() + "do"s + nll(doNode)); + temp.push_back(indent() + "do"s + nl(doNode)); pushScope(); } transformBody(doNode->body, temp, usage, assignList); if (usage == ExpUsage::Closure) { popScope(); - *funcStart = anonFuncStart() + nll(doNode); + *funcStart = anonFuncStart() + nl(doNode); temp.push_back(indent() + anonFuncEnd()); popAnonVarArg(); popFunctionScope(); } else { popScope(); - temp.push_back(indent() + "end"s + nlr(doNode)); + temp.push_back(indent() + "end"s + nl(doNode)); } out.push_back(join(temp)); } @@ -10630,7 +10674,7 @@ private: auto code = "do\n\t"s + okVar + ", ... = try nil\n\t... if "s + okVar; auto doNode = toAst(code, x); auto block = doNode->body->content.to(); - auto asmt = static_cast(block->statements.front())->content.to(); + auto asmt = static_cast(block->statementOrComments.front())->content.to(); auto assign = asmt->action.to(); auto sVal = simpleSingleValueFrom(assign->values.back()); auto newTry = sVal->value.to(); @@ -10654,8 +10698,8 @@ private: tryFunc.set(tryNode->func); if (auto tryBlock = tryFunc.as()) { BLOCK_START - BREAK_IF(tryBlock->statements.size() != 1); - auto stmt = static_cast(tryBlock->statements.front()); + BREAK_IF(countStatementFrom(tryBlock) != 1); + auto stmt = firstStatementFrom(tryBlock); auto expListAssign = stmt->content.as(); BREAK_IF(!expListAssign); BREAK_IF(expListAssign->action); @@ -10719,7 +10763,7 @@ private: auto stmt = x->new_ptr(); stmt->content.set(expListAssign); auto block = x->new_ptr(); - block->statements.push_back(stmt); + block->statementOrComments.push_back(stmt); tryFunc.set(block); } } @@ -10747,7 +10791,7 @@ private: } if (usage == ExpUsage::Common) { out.back().insert(0, indent()); - out.back().append(nlr(x)); + out.back().append(nl(x)); } return; } @@ -10772,7 +10816,7 @@ private: } if (usage == ExpUsage::Common) { out.back().insert(0, indent()); - out.back().append(nlr(x)); + out.back().append(nl(x)); } return; } else if (auto value = singleValueFrom(tryFunc)) { @@ -10833,7 +10877,7 @@ private: } if (usage == ExpUsage::Common) { out.back().insert(0, indent()); - out.back().append(nlr(x)); + out.back().append(nl(x)); } return; BLOCK_END @@ -10852,7 +10896,7 @@ private: } if (usage == ExpUsage::Common) { out.back().insert(0, indent()); - out.back().append(nlr(x)); + out.back().append(nl(x)); } } @@ -10928,11 +10972,11 @@ private: if (objAssign) { auto preDef = toLocalDecl(transformAssignDefs(expList, DefOp::Mark)); if (!preDef.empty()) { - temp.push_back(preDef + nll(importNode)); + temp.push_back(preDef + nl(importNode)); } if (!currentScope().lastStatement) { extraScope = true; - temp.push_back(indent() + "do"s + nll(importNode)); + temp.push_back(indent() + "do"s + nl(importNode)); pushScope(); } transformAssignment(objAssign, temp); @@ -10944,7 +10988,7 @@ private: if (objAssign) { if (extraScope) { popScope(); - temp.push_back(indent() + "end"s + nlr(importNode)); + temp.push_back(indent() + "end"s + nl(importNode)); } } out.push_back(join(temp)); @@ -11234,7 +11278,7 @@ private: if (expList) { if (!currentScope().lastStatement) { extraScope = true; - temp.push_back(indent() + "do"s + nll(whileNode)); + temp.push_back(indent() + "do"s + nl(whileNode)); pushScope(); } } @@ -11243,13 +11287,13 @@ private: auto lenVar = getUnusedName("_len_"sv); addToScope(lenVar); auto breakLoopType = getBreakLoopType(whileNode->body, accumVar); - _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(whileNode); + _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(whileNode); temp.emplace_back(clearBuf()); - _buf << indent() << "local "s << lenVar << " = 1"s << nll(whileNode); + _buf << indent() << "local "s << lenVar << " = 1"s << nl(whileNode); auto& lenAssign = temp.emplace_back(clearBuf()); bool isUntil = _parser.toString(whileNode->type) == "until"sv; auto condStr = transformCondExp(whileNode->condition, isUntil); - temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); + temp.push_back(indent() + "while "s + condStr + " do"s + nl(whileNode)); pushScope(); if (hasBreakWithValue(breakLoopType)) { lenAssign.clear(); @@ -11264,7 +11308,7 @@ private: } } popScope(); - temp.push_back(indent() + "end"s + nlr(whileNode)); + temp.push_back(indent() + "end"s + nl(whileNode)); if (expList) { auto assign = x->new_ptr(); assign->values.push_back(toAst(accumVar, x)); @@ -11274,10 +11318,10 @@ private: transformAssignment(assignment, temp); if (extraScope) popScope(); } else { - temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); + temp.push_back(indent() + "return "s + accumVar + nl(whileNode)); } if (expList && extraScope) { - temp.push_back(indent() + "end"s + nlr(whileNode)); + temp.push_back(indent() + "end"s + nl(whileNode)); } out.push_back(join(temp)); } @@ -11299,12 +11343,12 @@ private: auto lenVar = getUnusedName("_len_"sv); addToScope(lenVar); auto breakLoopType = getBreakLoopType(whileNode->body, accumVar); - _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(whileNode); + _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(whileNode); temp.emplace_back(clearBuf()); - auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); + auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(whileNode)); bool isUntil = _parser.toString(whileNode->type) == "until"sv; auto condStr = transformCondExp(whileNode->condition, isUntil); - temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); + temp.push_back(indent() + "while "s + condStr + " do"s + nl(whileNode)); pushScope(); if (hasBreakWithValue(breakLoopType)) { lenAssign.clear(); @@ -11319,10 +11363,10 @@ private: } } popScope(); - temp.push_back(indent() + "end"s + nlr(whileNode)); - temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); + temp.push_back(indent() + "end"s + nl(whileNode)); + temp.push_back(indent() + "return "s + accumVar + nl(whileNode)); popScope(); - funcStart = anonFuncStart() + nll(whileNode); + funcStart = anonFuncStart() + nl(whileNode); temp.push_back(indent() + anonFuncEnd()); popAnonVarArg(); popFunctionScope(); @@ -11363,9 +11407,9 @@ private: auto breakLoopType = getBreakLoopType(whileNode->body, Empty); transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common); popScope(); - _buf << indent() << "while "sv << condStr << " do"sv << nll(whileNode); + _buf << indent() << "while "sv << condStr << " do"sv << nl(whileNode); _buf << temp.back(); - _buf << indent() << "end"sv << nlr(whileNode); + _buf << indent() << "end"sv << nl(whileNode); out.push_back(clearBuf()); } @@ -11376,7 +11420,7 @@ private: if (expList) { if (!currentScope().lastStatement) { extraScope = true; - temp.push_back(indent() + "do"s + nll(repeatNode)); + temp.push_back(indent() + "do"s + nl(repeatNode)); pushScope(); } } @@ -11385,12 +11429,12 @@ private: auto lenVar = getUnusedName("_len_"sv); addToScope(lenVar); auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar); - _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(repeatNode); + _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(repeatNode); temp.emplace_back(clearBuf()); - _buf << indent() << "local "s << lenVar << " = 1"s << nll(repeatNode); + _buf << indent() << "local "s << lenVar << " = 1"s << nl(repeatNode); auto& lenAssign = temp.emplace_back(clearBuf()); auto condStr = transformCondExp(repeatNode->condition, false); - temp.push_back(indent() + "repeat"s + nll(repeatNode)); + temp.push_back(indent() + "repeat"s + nl(repeatNode)); pushScope(); if (hasBreakWithValue(breakLoopType)) { lenAssign.clear(); @@ -11405,7 +11449,7 @@ private: } } popScope(); - temp.push_back(indent() + "until "s + condStr + nlr(repeatNode)); + temp.push_back(indent() + "until "s + condStr + nl(repeatNode)); if (expList) { auto assign = x->new_ptr(); assign->values.push_back(toAst(accumVar, x)); @@ -11415,10 +11459,10 @@ private: transformAssignment(assignment, temp); if (extraScope) popScope(); } else { - temp.push_back(indent() + "return "s + accumVar + nlr(repeatNode)); + temp.push_back(indent() + "return "s + accumVar + nl(repeatNode)); } if (expList && extraScope) { - temp.push_back(indent() + "end"s + nlr(repeatNode)); + temp.push_back(indent() + "end"s + nl(repeatNode)); } out.push_back(join(temp)); } @@ -11440,11 +11484,11 @@ private: auto lenVar = getUnusedName("_len_"sv); addToScope(lenVar); auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar); - _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(repeatNode); + _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(repeatNode); temp.emplace_back(clearBuf()); - auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nll(repeatNode)); + auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(repeatNode)); auto condStr = transformCondExp(repeatNode->condition, false); - temp.push_back(indent() + "repeat"s + nll(repeatNode)); + temp.push_back(indent() + "repeat"s + nl(repeatNode)); pushScope(); if (hasBreakWithValue(breakLoopType)) { lenAssign.clear(); @@ -11459,10 +11503,10 @@ private: } } popScope(); - temp.push_back(indent() + "until "s + condStr + nlr(repeatNode)); - temp.push_back(indent() + "return "s + accumVar + nlr(repeatNode)); + temp.push_back(indent() + "until "s + condStr + nl(repeatNode)); + temp.push_back(indent() + "return "s + accumVar + nl(repeatNode)); popScope(); - funcStart = anonFuncStart() + nll(repeatNode); + funcStart = anonFuncStart() + nl(repeatNode); temp.push_back(indent() + anonFuncEnd()); popAnonVarArg(); popFunctionScope(); @@ -11479,9 +11523,9 @@ private: temp.push_back(condVar); } popScope(); - _buf << indent() << "repeat"sv << nll(repeat); + _buf << indent() << "repeat"sv << nl(repeat); _buf << temp.front(); - _buf << indent() << "until "sv << temp.back() << nlr(repeat); + _buf << indent() << "until "sv << temp.back() << nl(repeat); out.push_back(clearBuf()); } @@ -11505,7 +11549,7 @@ private: if (switchNode->assignment) { if (needScope) { extraScope = true; - temp.push_back(indent() + "do"s + nll(x)); + temp.push_back(indent() + "do"s + nl(x)); pushScope(); } auto asmt = x->new_ptr(); @@ -11523,7 +11567,7 @@ private: if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { if (needScope && !extraScope) { extraScope = true; - temp.push_back(indent() + "do"s + nll(x)); + temp.push_back(indent() + "do"s + nl(x)); pushScope(); } } @@ -11553,13 +11597,13 @@ private: } if (tableMatching) { if (!firstBranch) { - temp.push_back(indent() + "else"s + nll(branch)); + temp.push_back(indent() + "else"s + nl(branch)); pushScope(); addScope++; } if (tabCheckVar.empty()) { if (!extraScope && needScope) { - temp.push_back(indent() + "do"s + nll(branch)); + temp.push_back(indent() + "do"s + nl(branch)); pushScope(); extraScope = true; } @@ -11567,17 +11611,17 @@ private: forceAddToScope(typeVar); tabCheckVar = getUnusedName("_tab_"sv); forceAddToScope(tabCheckVar); - temp.push_back(indent() + "local "s + typeVar + " = "s + globalVar("type"sv, branch, AccessType::Read) + '(' + objVar + ')' + nll(branch)); - temp.push_back(indent() + "local "s + tabCheckVar + " = \"table\" == "s + typeVar + " or \"userdata\" == "s + typeVar + nll(branch)); + temp.push_back(indent() + "local "s + typeVar + " = "s + globalVar("type"sv, branch, AccessType::Read) + '(' + objVar + ')' + nl(branch)); + temp.push_back(indent() + "local "s + tabCheckVar + " = \"table\" == "s + typeVar + " or \"userdata\" == "s + typeVar + nl(branch)); } std::string matchVar; bool lastBranch = branches.back() == branch_ && !switchNode->lastBranch; if (!lastBranch) { matchVar = getUnusedName("_match_"sv); forceAddToScope(matchVar); - temp.push_back(indent() + "local "s + matchVar + " = false"s + nll(branch)); + temp.push_back(indent() + "local "s + matchVar + " = false"s + nl(branch)); } - temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nll(branch)); + temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nl(branch)); pushScope(); auto chainValue = toAst(objVar, branch); auto assignment = assignmentFrom(static_cast(valueList->exprs.front()), newExp(chainValue, branch), branch); @@ -11620,21 +11664,21 @@ private: } } if (!conds.empty()) { - temp.push_back(indent() + "if "s + join(conds, " and "sv) + " then"s + nll(branch)); + temp.push_back(indent() + "if "s + join(conds, " and "sv) + " then"s + nl(branch)); pushScope(); } if (!lastBranch) { - temp.push_back(indent() + matchVar + " = true"s + nll(branch)); + temp.push_back(indent() + matchVar + " = true"s + nl(branch)); } transform_plain_body(branch->body, temp, usage, assignList); if (!conds.empty()) { popScope(); - temp.push_back(indent() + "end"s + nll(branch)); + temp.push_back(indent() + "end"s + nl(branch)); } if (!lastBranch) { popScope(); - temp.push_back(indent() + "end"s + nll(branch)); - temp.push_back(indent() + "if not "s + matchVar + " then"s + nll(branch)); + temp.push_back(indent() + "end"s + nl(branch)); + temp.push_back(indent() + "if not "s + matchVar + " then"s + nl(branch)); pushScope(); addScope++; } else { @@ -11654,7 +11698,7 @@ private: } temp.back().append(' ' + tmp.back() + " == "s + (exp == exprs.back() ? objVar : objVar + " or"s)); } - temp.back().append(" then"s + nll(branch)); + temp.back().append(" then"s + nl(branch)); pushScope(); transform_plain_body(branch->body, temp, usage, assignList); popScope(); @@ -11662,7 +11706,7 @@ private: } if (switchNode->lastBranch) { if (!firstBranch) { - temp.push_back(indent() + "else"s + nll(switchNode->lastBranch)); + temp.push_back(indent() + "else"s + nl(switchNode->lastBranch)); pushScope(); } else { addScope--; @@ -11672,20 +11716,20 @@ private: } while (addScope > 0) { addScope--; - temp.push_back(indent() + "end"s + nlr(switchNode)); + temp.push_back(indent() + "end"s + nl(switchNode)); popScope(); } - temp.push_back(indent() + "end"s + nlr(switchNode)); + temp.push_back(indent() + "end"s + nl(switchNode)); if (usage == ExpUsage::Closure) { popFunctionScope(); popScope(); - *funcStart = anonFuncStart() + nll(switchNode); + *funcStart = anonFuncStart() + nl(switchNode); temp.push_back(indent() + anonFuncEnd()); popAnonVarArg(); } if (extraScope) { popScope(); - temp.push_back(indent() + "end"s + nlr(switchNode)); + temp.push_back(indent() + "end"s + nl(switchNode)); } out.push_back(join(temp)); } @@ -11704,7 +11748,7 @@ private: } auto preDefine = toLocalDecl(defs); if (!preDefine.empty()) { - out.push_back(preDefine + nll(local)); + out.push_back(preDefine + nl(local)); } } } @@ -11909,7 +11953,7 @@ private: } str_list temp; if (localAttrib->forceLocal) { - temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); + temp.push_back(indent() + "local "s + join(vars, ", "sv) + nl(x)); } transformAssignment(assignment, temp); for (const auto& name : vars) { @@ -11955,13 +11999,13 @@ private: auto rit = items.begin(); str_list tmp; while (lit != vars.end()) { - tmp.push_back(indent() + "local "s + *lit + (target >= 504 ? " = "s : " = "s) + *rit + nll(x)); + tmp.push_back(indent() + "local "s + *lit + (target >= 504 ? " = "s : " = "s) + *rit + nl(x)); lit++; rit++; } temp.push_back(join(tmp)); } else { - temp.push_back(indent() + "local "s + join(vars, ", "sv) + " = "s + join(items, ", "sv) + nll(x)); + temp.push_back(indent() + "local "s + join(vars, ", "sv) + " = "s + join(items, ", "sv) + nl(x)); str_list leftVars; pushScope(); for (size_t i = 0; i < vars.size(); i++) { @@ -11982,7 +12026,7 @@ private: for (auto item : assignA->values.objects()) { transformAssignItem(item, items); } - temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nll(x)); + temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nl(x)); } for (const auto& var : vars) { markVarLocalConst(var); @@ -12007,7 +12051,7 @@ private: vars.push_back(item.targetVar); } } - temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); + temp.push_back(indent() + "local "s + join(vars, ", "sv) + nl(x)); transformAssignment(assignment, temp); for (const auto& name : vars) { markVarLocalConst(name); @@ -12028,7 +12072,7 @@ private: auto assignment = assignmentFrom(exp, breakLoop->value, breakLoop); transformAssignment(assignment, out); } - out.push_back(indent() + keyword + nll(breakLoop)); + out.push_back(indent() + keyword + nl(breakLoop)); return; } if (_continueVars.empty()) throw CompileError("continue is not inside a loop"sv, breakLoop); @@ -12041,8 +12085,8 @@ private: if (!temp.empty()) { _buf << temp.back(); } - _buf << indent() << item.var << " = true"sv << nll(breakLoop); - _buf << indent() << "break"sv << nll(breakLoop); + _buf << indent() << item.var << " = true"sv << nl(breakLoop); + _buf << indent() << "break"sv << nl(breakLoop); out.push_back(clearBuf()); } else { transformGoto(toAst("goto "s + item.var, breakLoop), temp); @@ -12068,7 +12112,7 @@ private: throw CompileError("label '"s + labelStr + "' already defined at line "s + std::to_string(it->second.line), label); } scope[labelStr] = {label->m_begin.m_line, static_cast(_scopes.size())}; - out.push_back(indent() + "::"s + labelStr + "::"s + nll(label)); + out.push_back(indent() + "::"s + labelStr + "::"s + nl(label)); } void transformGoto(Goto_t* gotoNode, str_list& out) { @@ -12077,7 +12121,7 @@ private: } auto labelStr = unicodeVariableFrom(gotoNode->label); gotos.push_back({gotoNode, labelStr, _gotoScopes.top(), static_cast(_scopes.size())}); - out.push_back(indent() + "goto "s + labelStr + nll(gotoNode)); + out.push_back(indent() + "goto "s + labelStr + nl(gotoNode)); } void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) { @@ -12141,13 +12185,13 @@ private: temp.push_back(getPreDefineLine(assignment)); } assignments.push_front(assignmentFrom(newValue, value, value)); - temp.push_back(indent() + "do"s + nll(x)); + temp.push_back(indent() + "do"s + nl(x)); pushScope(); for (auto item : assignments.objects()) { transformAssignment(static_cast(item), temp); } popScope(); - temp.push_back(indent() + "end"s + nll(x)); + temp.push_back(indent() + "end"s + nl(x)); out.push_back(join(temp)); } }; diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 5a54690..cacfebe 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -1082,48 +1082,35 @@ YueParser::YueParser() { IfLine = IfType >> space >> IfCond; WhileLine = WhileType >> space >> Exp; - YueLineComment = *(not_(set("\r\n")) >> any_char); - yue_line_comment = "--" >> YueLineComment >> and_(stop); - MultilineCommentInner = multi_line_content; - YueMultilineComment = multi_line_open >> MultilineCommentInner >> multi_line_close; - yue_comment = check_indent >> ( - ( - YueMultilineComment >> - *(set(" \t") | YueMultilineComment) >> - -yue_line_comment - ) | yue_line_comment - ) >> and_(line_break); - ChainAssign = Seperator >> Exp >> +(space >> '=' >> space >> Exp >> space >> and_('=')) >> space >> Assign; StatementAppendix = (IfLine | WhileLine | CompInner) >> space; Statement = - Seperator >> - -( - yue_comment >> - *(line_break >> yue_comment) >> - line_break >> - check_indent_match - ) >> - space >> ( + ( Import | While | Repeat | For | ForEach | Return | Local | Global | Export | Macro | MacroInPlace | BreakLoop | Label | Goto | ShortTabAppending | LocalAttrib | Backcall | PipeBody | ExpListAssign | ChainAssign | StatementAppendix >> empty_block_error | and_(key("else") | key("elseif") | key("when")) >> dangling_clause_error - ) >> - space >> + ) >> space >> -StatementAppendix; StatementSep = white >> (set("('\"") | "[[" | "[="); Body = in_block | Statement; - empty_line_break = - check_indent >> (multi_line_comment >> space | comment) >> and_(stop) | - advance >> ensure(multi_line_comment >> space | comment, pop_indent) >> and_(stop) | - plain_space >> and_(line_break); + YueLineComment = *(not_(set("\r\n")) >> any_char); + yue_line_comment = "--" >> YueLineComment >> and_(stop); + YueMultilineComment = multi_line_content; + yue_multiline_comment = multi_line_open >> YueMultilineComment >> multi_line_close; + comment_line = + yue_multiline_comment >> *(set(" \t") | yue_multiline_comment) >> plain_space >> -yue_line_comment | + yue_line_comment; + YueComment = + check_indent >> comment_line >> and_(stop) | + advance >> ensure(comment_line, pop_indent) >> and_(stop) | + plain_space >> and_(stop); indentation_error = pl::user(not_(pipe_operator | eof()), [](const item_t& item) { RaiseError("unexpected indent"sv, item); @@ -1131,18 +1118,18 @@ YueParser::YueParser() { }); line = ( - check_indent_match >> Statement | - empty_line_break | + check_indent_match >> space >> Statement | + YueComment | advance_match >> ensure(space >> (indentation_error | Statement), pop_indent) ); Block = Seperator >> (pl::user(true_(), [](const item_t& item) { State* st = reinterpret_cast(item.user_data); return st->lax; - }) >> lax_line >> *(+line_break >> lax_line) | line >> *(+line_break >> line)); + }) >> lax_line >> *(line_break >> lax_line) | line >> *(line_break >> line)); shebang = "#!" >> *(not_(stop) >> any_char); - BlockEnd = Block >> white >> stop; - File = -shebang >> -Block >> white >> stop; + BlockEnd = Block >> stop; + File = -shebang >> -Block >> stop; lax_line = advance_match >> ensure(*(not_(stop) >> any()), pop_indent) | line >> and_(stop) | check_indent_match >> *(not_(stop) >> any()); } diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 3aca4ef..3b1cd61 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h @@ -308,9 +308,9 @@ private: NONE_AST_RULE(must_exp); NONE_AST_RULE(must_unary_exp); NONE_AST_RULE(local_const_item); - NONE_AST_RULE(empty_line_break); - NONE_AST_RULE(yue_comment); + NONE_AST_RULE(comment_line); NONE_AST_RULE(yue_line_comment); + NONE_AST_RULE(yue_multiline_comment); NONE_AST_RULE(line); NONE_AST_RULE(shebang); NONE_AST_RULE(lax_line); @@ -471,8 +471,8 @@ private: AST_RULE(Statement); AST_RULE(StatementSep); AST_RULE(YueLineComment); - AST_RULE(MultilineCommentInner); AST_RULE(YueMultilineComment); + AST_RULE(YueComment); AST_RULE(ChainAssign); AST_RULE(Body); AST_RULE(Block); diff --git a/src/yuescript/yuescript.cpp b/src/yuescript/yuescript.cpp index 52236bf..6089894 100644 --- a/src/yuescript/yuescript.cpp +++ b/src/yuescript/yuescript.cpp @@ -185,6 +185,11 @@ static int yueformat(lua_State* L) { if (!lua_isnoneornil(L, 2)) { tabSize = static_cast(luaL_checkinteger(L, 2)); } + bool reserveComment = true; + if (!lua_isnoneornil(L, 3)) { + luaL_checktype(L, 3, LUA_TBOOLEAN); + reserveComment = lua_toboolean(L, 3) != 0; + } std::string_view codes(input, len); auto info = yue::YueParser::shared().parse(codes, false); if (info.error) { @@ -206,8 +211,11 @@ static int yueformat(lua_State* L) { } else { formatter.spaceOverTab = false; } + formatter.reserveComment = reserveComment; auto result = formatter.toString(info.node.get()); - yue::Utils::replace(result, "\n\n", "\n"); + if (!formatter.reserveComment) { + yue::Utils::replace(result, "\n\n", "\n"); + } lua_pushlstring(L, result.c_str(), result.size()); return 1; } @@ -295,6 +303,11 @@ static int yuetoast(lua_State* L) { luaL_checktype(L, 4, LUA_TBOOLEAN); lax = lua_toboolean(L, 4) != 0; } + bool reserveComment = false; + if (!lua_isnoneornil(L, 5)) { + luaL_checktype(L, 5, LUA_TBOOLEAN); + reserveComment = lua_toboolean(L, 5) != 0; + } auto& yueParser = yue::YueParser::shared(); auto info = ruleName.empty() ? yueParser.parse({input, size}, lax) : yueParser.parse(ruleName, {input, size}, lax); if (!info.error) { @@ -322,13 +335,11 @@ static int yuetoast(lua_State* L) { }; do_call(info.node); yue::YueFormat formatter{}; + formatter.reserveComment = reserveComment; while (!stack.empty()) { auto& current = stack.top(); int continuation = current.continuation; auto node = current.node; - if (auto comment = yue::ast_cast(node)) { - node = comment->inner.get(); - } switch (continuation) { case 0: { if (!current.children) { @@ -337,6 +348,9 @@ static int yuetoast(lua_State* L) { current.hasSep = true; return false; } + if (!reserveComment && yue::ast_is(child)) { + return false; + } if (!current.children) { current.children = std::make_unique>(); } -- cgit v1.2.3-55-g6feb