From b6725202f4a8cac5f829dac9a72a81f3ff73e787 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Wed, 21 Oct 2020 23:44:50 +0800 Subject: extend macro feature to support compiling Moonscript to other Lua dialect like teal. add examples for how to write MoonPlus codes that compile to teal. fix C++ macro to build without MoonPlus macro feature or built-in Lua. add support for passing arguments from command line to compiler that can be accessed or altered by "require('moonp').options". --- src/MoonP/moon_ast.h | 2 +- src/MoonP/moon_compiler.cpp | 198 +++++++++++++++++++++++++++++++++++--------- src/MoonP/moon_compiler.h | 15 +++- src/MoonP/moon_parser.cpp | 2 +- src/MoonP/moonplus.cpp | 26 +++--- src/MoonP/moonplus.h | 2 +- src/moonp.cpp | 37 ++++++--- 7 files changed, 215 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/MoonP/moon_ast.h b/src/MoonP/moon_ast.h index 7e480b5..02428ca 100644 --- a/src/MoonP/moon_ast.h +++ b/src/MoonP/moon_ast.h @@ -636,7 +636,7 @@ AST_LEAF(macro_type) AST_END(macro_type) AST_NODE(MacroName) - ast_ptr name; + ast_ptr name; AST_MEMBER(MacroName, &name) AST_END(MacroName) diff --git a/src/MoonP/moon_compiler.cpp b/src/MoonP/moon_compiler.cpp index debc43a..f24441f 100644 --- a/src/MoonP/moon_compiler.cpp +++ b/src/MoonP/moon_compiler.cpp @@ -53,7 +53,7 @@ inline std::string s(std::string_view sv) { return std::string(sv); } -const std::string_view version = "0.4.18"sv; +const std::string_view version = "0.4.19"sv; const std::string_view extension = "mp"sv; class MoonCompilerImpl { @@ -89,10 +89,17 @@ public: } #endif // MOONP_NO_MACRO - std::tuple compile(std::string_view codes, const MoonConfig& config) { + CompileInfo compile(std::string_view codes, const MoonConfig& config) { _config = config; +#ifndef MOONP_NO_MACRO + if (L) passOptions(); +#endif // MOONP_NO_MACRO _info = _parser.parse(codes); - GlobalVars globals; + std::unique_ptr globals; + std::unique_ptr options; + if (!config.options.empty()) { + options = std::make_unique(config.options); + } DEFER(clear()); if (_info.node) { try { @@ -104,19 +111,39 @@ public: nullptr, true); popScope(); if (config.lintGlobalVariable) { - globals = std::make_unique>(); + globals = std::make_unique(); for (const auto& var : _globals) { int line,col; std::tie(line,col) = var.second; globals->push_back({var.first, line, col}); } } - return {std::move(out.back()), Empty, std::move(globals)}; +#ifndef MOONP_NO_MACRO + if (L) { + int top = lua_gettop(L); + DEFER(lua_settop(L, top)); + if (!options) { + options = std::make_unique(); + } + pushMoonp("options"sv); + lua_pushnil(L); // options startKey + while (lua_next(L, -2) != 0) { // options key value + size_t len = 0; + auto pstr = lua_tolstring(L, -2, &len); + std::string key{pstr, len}; + pstr = lua_tolstring(L, -1, &len); + std::string value{pstr, len}; + (*options)[key] = value; + lua_pop(L, 1); // options key + } + } +#endif // MOONP_NO_MACRO + return {std::move(out.back()), Empty, std::move(globals), std::move(options)}; } catch (const std::logic_error& error) { - return {Empty, error.what(), std::move(globals)}; + return {Empty, error.what(), std::move(globals), std::move(options)}; } } else { - return {Empty, std::move(_info.error), std::move(globals)}; + return {Empty, std::move(_info.error), std::move(globals), std::move(options)}; } } @@ -2150,6 +2177,17 @@ private: } #ifndef MOONP_NO_MACRO + void passOptions() { + if (!_config.options.empty()) { + pushMoonp("options"sv); // options + for (const auto& option : _config.options) { + lua_pushlstring(L, option.second.c_str(), option.second.size()); + lua_setfield(L, -2, option.first.c_str()); + } + lua_pop(L, 1); + } + } + void pushCurrentModule() { if (_useModule) { lua_pushliteral(L, MOONP_MODULE); // MOONP_MODULE @@ -2165,6 +2203,7 @@ private: if (_luaOpen) { _luaOpen(static_cast(L)); } + passOptions(); _stateOwner = true; } lua_pushliteral(L, MOONP_MODULE); // MOONP_MODULE @@ -2314,7 +2353,7 @@ private: out.push_back(Empty); } #else - void transformMacro(Macro_t* macro, str_list& out, bool exporting) { + void transformMacro(Macro_t* macro, str_list&, bool) { throw std::logic_error(_info.errorMessage("macro feature not supported"sv, macro)); } #endif // MOONP_NO_MACRO @@ -3023,16 +3062,67 @@ private: } #ifndef MOONP_NO_MACRO - std::pair expandMacroStr(ChainValue_t* chainValue) { + std::tuple expandMacroStr(ChainValue_t* chainValue) { const auto& chainList = chainValue->items.objects(); auto x = ast_to(chainList.front())->item.to(); - auto macroName = _parser.toString(x->name); - if (!_useModule) { + auto macroName = x->name ? _parser.toString(x->name) : Empty; + if (!macroName.empty() && !_useModule) { throw std::logic_error(_info.errorMessage("can not resolve macro"sv, x)); } pushCurrentModule(); // cur int top = lua_gettop(L) - 1; DEFER(lua_settop(L, top)); + if (macroName.empty()) { + lua_pop(L, 1); // empty + auto item = *(++chainList.begin()); + const node_container* args = nullptr; + if (auto invoke = ast_cast(item)) { + args = &invoke->args.objects(); + } else { + args = &ast_to(item)->args.objects(); + } + if (args->size() != 1) { + throw std::logic_error(_info.errorMessage("in-place macro must be followed by a compile time function"sv, x)); + } + auto fcodes = _parser.toString(args->back()); + Utils::trim(fcodes); + pushMoonp("loadstring"sv); // loadstring + lua_pushlstring(L, fcodes.c_str(), fcodes.size()); // loadstring codes + lua_pushliteral(L, "=(macro in-place)"); // loadstring codes chunk + pushOptions(args->back()->m_begin.m_line - 1); // loadstring codes chunk options + if (lua_pcall(L, 3, 2, 0) != 0) { // loadstring(codes,chunk,options), f err + std::string err = lua_tostring(L, -1); + throw std::logic_error(_info.errorMessage(s("fail to load macro codes\n"sv) + err, x)); + } // f err + if (lua_isnil(L, -2) != 0) { // f == nil, f err + std::string err = lua_tostring(L, -1); + throw std::logic_error(_info.errorMessage(s("fail to load macro codes, at (macro in-place): "sv) + err, x)); + } + lua_pop(L, 1); // f + pushMoonp("pcall"sv); // f pcall + lua_insert(L, -2); // pcall f + if (lua_pcall(L, 1, 2, 0) != 0) { // f(), success macroFunc + std::string err = lua_tostring(L, -1); + throw std::logic_error(_info.errorMessage(s("fail to generate macro function\n"sv) + err, x)); + } // success res + if (lua_toboolean(L, -2) == 0) { + std::string err = lua_tostring(L, -1); + throw std::logic_error(_info.errorMessage(s("fail to generate macro function\n"sv) + err, x)); + } // true macroFunc + lua_remove(L, -2); // macroFunc + pushMoonp("pcall"sv); // macroFunc pcall + lua_insert(L, -2); // pcall macroFunc + bool success = lua_pcall(L, 1, 2, 0) == 0; + if (!success) { // err + std::string err = lua_tostring(L, -1); + throw std::logic_error(_info.errorMessage(s("fail to expand macro: "sv) + err, x)); + } // success err + if (lua_toboolean(L, -2) == 0) { + std::string err = lua_tostring(L, -1); + throw std::logic_error(_info.errorMessage(s("fail to expand macro: "sv) + err, x)); + } + return {s("block"sv), Empty, {}}; + } lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macroName lua_rawget(L, -2); // cur[macroName], cur macro if (lua_istable(L, -1) == 0) { @@ -3060,9 +3150,7 @@ private: BREAK_IF(!chainValue); BREAK_IF(!isMacroChain(chainValue)); BREAK_IF(chainValue->items.size() != 2); - std::string type, codes; - std::tie(type, codes) = expandMacroStr(chainValue); - str = codes; + str = std::get<1>(expandMacroStr(chainValue)); BLOCK_END if (str.empty()) { // exp is reassembled due to backcall expressions @@ -3092,30 +3180,55 @@ private: Utils::replace(str, "\r\n"sv, "\n"sv); lua_pushlstring(L, str.c_str(), str.size()); } // cur macro pcall func args... - bool success = lua_pcall(L, static_cast(args->size()) + 1, 2, 0) == 0; + bool success = lua_pcall(L, static_cast(args->size()) + 1, 3, 0) == 0; if (!success) { // cur macro err std::string err = lua_tostring(L, -1); throw std::logic_error(_info.errorMessage(s("fail to expand macro: "sv) + err, x)); - } // cur macro success res - if (lua_toboolean(L, -2) == 0) { - std::string err = lua_tostring(L, -1); + } // cur macro success res option + if (lua_toboolean(L, -3) == 0) { + std::string err = lua_tostring(L, -2); throw std::logic_error(_info.errorMessage(s("fail to expand macro: "sv) + err, x)); } - lua_remove(L, -2); // cur macro res - if (lua_isstring(L, -1) == 0) { + lua_remove(L, -3); // cur macro res option + if (lua_isstring(L, -2) == 0) { throw std::logic_error(_info.errorMessage(s("macro function must return string with expanded codes"sv), x)); - } // cur macro codes - lua_rawgeti(L, -2, 2); // cur macro codes type + } // cur macro codes option + lua_rawgeti(L, -3, 2); // cur macro codes option type std::string type = lua_tostring(L, -1); + lua_pop(L, 1); // cur macro codes option + str_list localVars; + if (lua_isnil(L, -1) == 0) { + if (lua_istable(L, -1) == 0) { + throw std::logic_error(_info.errorMessage(s("macro function must return expanded codes followed by a config table"sv), x)); + } + if (type == "expr"sv || type == "block"sv) { + throw std::logic_error(_info.errorMessage(s("expr or block macro is not accepting config table"sv), x)); + } + for (int i = 0; i < static_cast(lua_objlen(L, -1)); i++) { + lua_rawgeti(L, -1, i + 1); // cur macro codes option item + size_t len = 0; + if (lua_isstring(L, -1) == 0) { + throw std::logic_error(_info.errorMessage(s("macro config table must contains strings"sv), x)); + } + auto name = lua_tolstring(L, -1, &len); + if (_parser.match({name, len})) { + localVars.push_back(std::string(name, len)); + } else { + throw std::logic_error(_info.errorMessage(s("macro config table must contains names for local variables, got \""sv) + std::string(name, len) + '"', x)); + } + lua_pop(L, 1); + } + } // cur macro codes option std::string codes = lua_tostring(L, -2); - return {type, codes}; + return {type, codes, std::move(localVars)}; } - std::tuple, std::unique_ptr, std::string> expandMacro(ChainValue_t* chainValue, ExpUsage usage, bool allowBlockMacroReturn) { + std::tuple, std::unique_ptr, std::string, str_list> expandMacro(ChainValue_t* chainValue, ExpUsage usage, bool allowBlockMacroReturn) { auto x = ast_to(chainValue->items.front())->item.to(); const auto& chainList = chainValue->items.objects(); std::string type, codes; - std::tie(type, codes) = expandMacroStr(chainValue); + str_list localVars; + std::tie(type, codes, localVars) = expandMacroStr(chainValue); std::string targetType(usage != ExpUsage::Common || chainList.size() > 2 ? "expr"sv : "block"sv); if (type == "lua"sv) { if (!allowBlockMacroReturn && targetType != "block"sv) { @@ -3128,19 +3241,19 @@ private: std::string err = lua_tostring(L, -1); throw std::logic_error(_info.errorMessage(err, x)); } - return {nullptr, nullptr, std::move(codes)}; + return {nullptr, nullptr, std::move(codes), std::move(localVars)}; } else if (type == "text"sv) { if (!allowBlockMacroReturn && targetType != "block"sv) { throw std::logic_error(_info.errorMessage("text macro can only be placed where block macro is allowed"sv, x)); } - return {nullptr, nullptr, std::move(codes)}; + return {nullptr, nullptr, std::move(codes), std::move(localVars)}; } else if (!allowBlockMacroReturn && type != targetType) { throw std::logic_error(_info.errorMessage(s("macro type mismatch, "sv) + targetType + s(" expected, got "sv) + type, x)); } ParseInfo info; if (usage == ExpUsage::Common) { if (codes.empty()) { - return {x->new_ptr().get(), std::move(info.codes), Empty}; + return {x->new_ptr().get(), std::move(info.codes), Empty, std::move(localVars)}; } if (type == "expr"sv) { info = _parser.parse(codes); @@ -3202,7 +3315,7 @@ private: info.node.set(exp); } } - return {info.node, std::move(info.codes), Empty}; + return {info.node, std::move(info.codes), Empty, std::move(localVars)}; } #endif // MOONP_NO_MACRO @@ -3212,10 +3325,11 @@ private: ast_ptr node; std::unique_ptr codes; std::string luaCodes; - std::tie(node, codes, luaCodes) = expandMacro(chainValue, usage, allowBlockMacroReturn); + str_list localVars; + std::tie(node, codes, luaCodes, localVars) = expandMacro(chainValue, usage, allowBlockMacroReturn); Utils::replace(luaCodes, "\r\n"sv, "\n"sv); Utils::trim(luaCodes); - if (!node && !codes) { + if (!node) { if (!luaCodes.empty()) { if (_config.reserveLineNumber) { luaCodes.insert(0, nll(chainValue).substr(1)); @@ -3223,6 +3337,11 @@ private: luaCodes.append(nlr(chainValue)); } out.push_back(luaCodes); + if (!localVars.empty()) { + for (const auto& var : localVars) { + addToScope(var); + } + } return; } if (usage == ExpUsage::Common || (usage == ExpUsage::Return && node.is())) { @@ -3254,6 +3373,7 @@ private: } return; #else + (void)allowBlockMacroReturn; throw std::logic_error(_info.errorMessage("macro feature not supported"sv, chainValue)); #endif // MOONP_NO_MACRO } @@ -4983,11 +5103,9 @@ private: config.lintGlobalVariable = false; config.reserveLineNumber = false; config.implicitReturnRoot = _config.implicitReturnRoot; - std::string codes, err; - GlobalVars globals; - std::tie(codes, err, globals) = compiler.compile(text, config); - if (codes.empty() && !err.empty()) { - throw std::logic_error(_info.errorMessage(s("fail to compile module '"sv) + moduleName + s("\': "sv) + err, x)); + auto result = compiler.compile(text, config); + if (result.codes.empty() && !result.error.empty()) { + throw std::logic_error(_info.errorMessage(s("fail to compile module '"sv) + moduleName + s("\': "sv) + result.error, x)); } lua_pop(L, 1); // cur } @@ -5325,12 +5443,16 @@ MoonCompiler::MoonCompiler(void* sharedState, #ifndef MOONP_NO_MACRO _compiler(std::make_unique(static_cast(sharedState), luaOpen, sameModule)) {} #else -_compiler(std::make_unique()) {} +_compiler(std::make_unique()) { + (void)sharedState; + (void)luaOpen; + (void)sameModule; +} #endif // MOONP_NO_MACRO MoonCompiler::~MoonCompiler() {} -std::tuple MoonCompiler::compile(std::string_view codes, const MoonConfig& config) { +CompileInfo MoonCompiler::compile(std::string_view codes, const MoonConfig& config) { return _compiler->compile(codes, config); } diff --git a/src/MoonP/moon_compiler.h b/src/MoonP/moon_compiler.h index cb57d57..a1a5ce5 100644 --- a/src/MoonP/moon_compiler.h +++ b/src/MoonP/moon_compiler.h @@ -13,6 +13,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include #include namespace MoonP { @@ -20,12 +21,15 @@ namespace MoonP { extern const std::string_view version; extern const std::string_view extension; +using Options = std::unordered_map; + struct MoonConfig { bool lintGlobalVariable = false; bool implicitReturnRoot = true; bool reserveLineNumber = true; bool useSpaceOverTab = false; int lineOffset = 0; + Options options; }; struct GlobalVar { @@ -34,7 +38,14 @@ struct GlobalVar { int col; }; -using GlobalVars = std::unique_ptr>; +using GlobalVars = std::list; + +struct CompileInfo { + std::string codes; + std::string error; + std::unique_ptr globals; + std::unique_ptr options; +}; class MoonCompilerImpl; @@ -44,7 +55,7 @@ public: const std::function& luaOpen = nullptr, bool sameModule = false); virtual ~MoonCompiler(); - std::tuple compile(std::string_view codes, const MoonConfig& config = {}); + CompileInfo compile(std::string_view codes, const MoonConfig& config = {}); private: std::unique_ptr _compiler; }; diff --git a/src/MoonP/moon_parser.cpp b/src/MoonP/moon_parser.cpp index e984997..63eabb3 100644 --- a/src/MoonP/moon_parser.cpp +++ b/src/MoonP/moon_parser.cpp @@ -509,7 +509,7 @@ MoonParser::MoonParser() { fn_arrow = expr("->") | expr("=>"); FunLit = -FnArgsDef >> Space >> fn_arrow >> -Body; - MacroName = expr('$') >> Name; + MacroName = expr('$') >> -Name; macro_type = expr("expr") | expr("block") | expr("lua") | expr("text"); macro_args_def = sym('(') >> White >> -FnArgDefList >> White >> sym(')'); MacroLit = -macro_args_def >> Space >> expr("->") >> Body; diff --git a/src/MoonP/moonplus.cpp b/src/MoonP/moonplus.cpp index c775d75..bea1d6e 100644 --- a/src/MoonP/moonplus.cpp +++ b/src/MoonP/moonplus.cpp @@ -84,23 +84,21 @@ static int moontolua(lua_State* L) { lua_pop(L, 1); } std::string s(input, size); - std::string codes, err; - MoonP::GlobalVars globals; - std::tie(codes, err, globals) = MoonP::MoonCompiler(L, nullptr, sameModule).compile(s, config); - if (codes.empty() && !err.empty()) { + auto result = MoonP::MoonCompiler(L, nullptr, sameModule).compile(s, config); + if (result.codes.empty() && !result.error.empty()) { lua_pushnil(L); } else { - lua_pushlstring(L, codes.c_str(), codes.size()); + lua_pushlstring(L, result.codes.c_str(), result.codes.size()); } - if (err.empty()) { + if (result.error.empty()) { lua_pushnil(L); } else { - lua_pushlstring(L, err.c_str(), err.size()); + lua_pushlstring(L, result.error.c_str(), result.error.size()); } - if (globals) { - lua_createtable(L, static_cast(globals->size()), 0); + if (result.globals) { + lua_createtable(L, static_cast(result.globals->size()), 0); int i = 1; - for (const auto& var : *globals) { + for (const auto& var : *result.globals) { lua_createtable(L, 3, 0); lua_pushlstring(L, var.name.c_str(), var.name.size()); lua_rawseti(L, -2, 1); @@ -124,9 +122,11 @@ int luaopen_moonp(lua_State* L) { lua_pushcfunction(L, moontolua); // package loaded moonp func lua_setfield(L, -2, "to_lua"); // moonp["to_lua"] = func, package loaded moonp lua_pushlstring(L, &MoonP::version.front(), MoonP::version.size()); // package loaded moonp version - lua_setfield(L, -2, "version"); // loaded["version"] = version, package loaded moonp - lua_pushlstring(L, &MoonP::extension.front(), MoonP::extension.size()); // package loaded moonp ext - lua_setfield(L, -2, "extension"); // loaded["extension"] = ext, package loaded moonp + lua_setfield(L, -2, "version"); // moonp["version"] = version, package loaded moonp + lua_createtable(L, 0, 0); // package loaded moonp options + lua_pushlstring(L, &MoonP::extension.front(), MoonP::extension.size()); // package loaded moonp options ext + lua_setfield(L, -2, "extension"); // options["extension"] = ext, package loaded moonp options + lua_setfield(L, -2, "options"); // moonp["options"] = options, package loaded moonp lua_pushcfunction(L, init_stacktraceplus); // package loaded moonp func1 lua_setfield(L, -2, "load_stacktraceplus"); // moonp["load_stacktraceplus"] = func1, package loaded moonp lua_setfield(L, -2, "moonp"); // loaded["moonp"] = moonp, package loaded diff --git a/src/MoonP/moonplus.h b/src/MoonP/moonplus.h index b18ab64..ff82e9f 100644 --- a/src/MoonP/moonplus.h +++ b/src/MoonP/moonplus.h @@ -73,7 +73,7 @@ get_options = function(...) end end create_moonpath = function(package_path) - local extension = moonp.extension + local extension = moonp.options.extension local moonpaths do local _accum_0 = { } diff --git a/src/moonp.cpp b/src/moonp.cpp index 25be015..1e4302e 100644 --- a/src/moonp.cpp +++ b/src/moonp.cpp @@ -24,7 +24,7 @@ using namespace std::string_view_literals; #include "ghc/fs_std.hpp" #include "linenoise.hpp" -#ifndef MOONP_NO_MACRO +#if not (defined MOONP_NO_MACRO && defined MOONP_COMPILER_ONLY) #define _DEFER(code,line) std::shared_ptr _defer_##line(nullptr, [&](auto){code;}) #define DEFER(code) _DEFER(code,__LINE__) extern "C" { @@ -71,7 +71,9 @@ void pushOptions(lua_State* L, int lineOffset) { lua_pushinteger(L, lineOffset); lua_rawset(L, -3); } +#endif // not (defined MOONP_NO_MACRO && defined MOONP_COMPILER_ONLY) +#ifndef MOONP_NO_MACRO #define MOONP_ARGS nullptr,openlibs #else #define MOONP_ARGS @@ -278,12 +280,12 @@ int main(int narg, const char** args) { conf.reserveLineNumber = false; conf.useSpaceOverTab = true; auto result = MoonP::MoonCompiler{MOONP_ARGS}.compile(codes, conf); - if (std::get<1>(result).empty()) { - std::cout << std::get<0>(result); + if (result.error.empty()) { + std::cout << result.codes; return 0; } else { std::ostringstream buf; - std::cout << std::get<1>(result) << '\n'; + std::cout << result.error << '\n'; return 1; } #ifndef MOONP_COMPILER_ONLY @@ -376,6 +378,12 @@ int main(int narg, const char** args) { std::cout << help; return 1; } + } else if (arg.substr(0, 1) == "-"sv && arg.find('=') != std::string::npos) { + auto argStr = arg.substr(1); + size_t idx = argStr.find('='); + auto key = argStr.substr(0, idx); + auto value = argStr.substr(idx + 1); + config.options[key] = value; } else { if (fs::is_directory(arg)) { for (auto item : fs::recursive_directory_iterator(arg)) { @@ -412,7 +420,7 @@ int main(int narg, const char** args) { auto start = std::chrono::high_resolution_clock::now(); auto result = MoonP::MoonCompiler{MOONP_ARGS}.compile(s, config); auto end = std::chrono::high_resolution_clock::now(); - if (!std::get<0>(result).empty()) { + if (!result.codes.empty()) { std::chrono::duration diff = end - start; start = std::chrono::high_resolution_clock::now(); MoonP::MoonParser{}.parse(s); @@ -426,15 +434,22 @@ int main(int narg, const char** args) { } else { std::ostringstream buf; buf << "Fail to compile: "sv << file.first << ".\n"sv; - buf << std::get<1>(result) << '\n'; + buf << result.error << '\n'; return std::tuple{1, file.first, buf.str()}; } } auto result = MoonP::MoonCompiler{MOONP_ARGS}.compile(s, config); - if (std::get<1>(result).empty()) { + if (result.error.empty()) { if (!writeToFile) { - return std::tuple{0, file.first, std::get<0>(result) + '\n'}; + return std::tuple{0, file.first, result.codes + '\n'}; } else { + std::string targetExtension("lua"sv); + if (result.options) { + auto it = result.options->find("target_extension"); + if (it != result.options->end()) { + targetExtension = it->second; + } + } fs::path targetFile; if (!resultFile.empty()) { targetFile = resultFile; @@ -444,14 +459,14 @@ int main(int narg, const char** args) { } else { targetFile = file.first; } - targetFile.replace_extension(".lua"sv); + targetFile.replace_extension('.' + targetExtension); } if (!targetPath.empty()) { fs::create_directories(targetFile.parent_path()); } std::ofstream output(targetFile, std::ios::trunc | std::ios::out); if (output) { - const auto& codes = std::get<0>(result); + const auto& codes = result.codes; if (config.reserveLineNumber) { auto head = std::string("-- [moonp]: "sv) + file.first + '\n'; output.write(head.c_str(), head.size()); @@ -465,7 +480,7 @@ int main(int narg, const char** args) { } else { std::ostringstream buf; buf << "Fail to compile: "sv << file.first << ".\n"; - buf << std::get<1>(result) << '\n'; + buf << result.error << '\n'; return std::tuple{1, std::string(), buf.str()}; } } else { -- cgit v1.2.3-55-g6feb