From 303834e1b1e6cd9cae64b66c2ae44dcd7185238f Mon Sep 17 00:00:00 2001 From: Li Jin Date: Sun, 24 Jul 2022 22:13:08 +0800 Subject: add option --target=5.1 to generate Lua 5.1 compatible codes. add const destructure. make import item const by default. --- src/yue.cpp | 39 ++++--- src/yuescript/yue_ast.h | 24 +++-- src/yuescript/yue_compiler.cpp | 232 ++++++++++++++++++++++++++++++++--------- src/yuescript/yue_parser.cpp | 42 +++++--- src/yuescript/yue_parser.h | 8 +- src/yuescript/yuescript.cpp | 10 +- 6 files changed, 256 insertions(+), 99 deletions(-) (limited to 'src') diff --git a/src/yue.cpp b/src/yue.cpp index 3e30c70..cb27db8 100644 --- a/src/yue.cpp +++ b/src/yue.cpp @@ -21,6 +21,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include using namespace std::string_view_literals; +using namespace std::string_literals; #include "ghc/fs_std.hpp" #include "linenoise.hpp" @@ -91,10 +92,10 @@ static const char luaminifyCodes[] = static void pushLuaminify(lua_State* L) { if (luaL_loadbuffer(L, luaminifyCodes, sizeof(luaminifyCodes) / sizeof(luaminifyCodes[0]) - 1, "=(luaminify)") != 0) { - std::string err = std::string("failed to load luaminify module.\n") + lua_tostring(L, -1); + std::string err = "failed to load luaminify module.\n"s + lua_tostring(L, -1); luaL_error(L, err.c_str()); } else if (lua_pcall(L, 0, 1, 0) != 0) { - std::string err = std::string("failed to init luaminify module.\n") + lua_tostring(L, -1); + std::string err = "failed to init luaminify module.\n"s + lua_tostring(L, -1); luaL_error(L, err.c_str()); } } @@ -209,7 +210,7 @@ int main(int narg, const char** args) { DEFER(lua_settop(L, top)); pushYue(L, "loadstring"sv); lua_pushlstring(L, codes.c_str(), codes.size()); - lua_pushstring(L, (std::string("=(repl ") + std::to_string(count) + ')').c_str()); + lua_pushstring(L, ("=(repl "s + std::to_string(count) + ')').c_str()); pushOptions(L, -1); const std::string_view Err = "\033[35m"sv, Val = "\033[33m"sv, Stop = "\033[0m\n"sv; if (lua_pcall(L, 3, 2, 0) != 0) { @@ -218,7 +219,7 @@ int main(int narg, const char** args) { } if (lua_isnil(L, -2) != 0) { std::string err = lua_tostring(L, -1); - auto modName = std::string("(repl "sv) + std::to_string(count) + "):"; + auto modName = "(repl "s + std::to_string(count) + "):"s; if (err.substr(0, modName.size()) == modName) { err = err.substr(modName.size()); } @@ -409,8 +410,8 @@ int main(int narg, const char** args) { std::cout << help; return 1; } - } else if (arg.size() > 1 && arg.substr(0, 1) == "-"sv && arg.substr(1, 1) != "-"sv) { - auto argStr = arg.substr(1); + } else if (arg.size() > 2 && arg.substr(0, 2) == "--"sv && arg.substr(2, 1) != "-"sv) { + auto argStr = arg.substr(2); yue::Utils::trim(argStr); size_t idx = argStr.find('='); if (idx != std::string::npos) { @@ -420,7 +421,7 @@ int main(int narg, const char** args) { yue::Utils::trim(value); config.options[key] = value; } else { - config.options[argStr] = ""; + config.options[argStr] = std::string(); } } else { if (fs::is_directory(arg)) { @@ -459,7 +460,13 @@ int main(int narg, const char** args) { auto conf = config; conf.module = file.first; if (!workPath.empty()) { - conf.options["path"] = (fs::path(workPath) / "?.lua").string(); + auto it = conf.options.find("path"); + if (it != conf.options.end()) { + it->second += ';'; + it->second += (fs::path(workPath) / "?.lua"sv).string(); + } else { + conf.options["path"] = (fs::path(workPath) / "?.lua"sv).string(); + } } if (dumpCompileTime) { auto start = std::chrono::high_resolution_clock::now(); @@ -499,7 +506,7 @@ int main(int narg, const char** args) { } else { std::string targetExtension("lua"sv); if (result.options) { - auto it = result.options->find("target_extension"); + auto it = result.options->find("target_extension"s); if (it != result.options->end()) { targetExtension = it->second; } @@ -519,19 +526,19 @@ int main(int narg, const char** args) { fs::create_directories(targetFile.parent_path()); } if (result.codes.empty()) { - return std::tuple{0, targetFile.string(), std::string("Built "sv) + file.first + '\n'}; + return std::tuple{0, targetFile.string(), "Built "s + file.first + '\n'}; } std::ofstream output(targetFile, std::ios::trunc | std::ios::out); if (output) { const auto& codes = result.codes; if (config.reserveLineNumber) { - auto head = std::string("-- [yue]: "sv) + file.first + '\n'; + auto head = "-- [yue]: "s + file.first + '\n'; output.write(head.c_str(), head.size()); } output.write(codes.c_str(), codes.size()); - return std::tuple{0, targetFile.string(), std::string("Built "sv) + file.first + '\n'}; + return std::tuple{0, targetFile.string(), "Built "s + file.first + '\n'}; } else { - return std::tuple{1, std::string(), std::string("Failed to write file: "sv) + targetFile.string() + '\n'}; + return std::tuple{1, std::string(), "Failed to write file: "s + targetFile.string() + '\n'}; } } } else { @@ -541,7 +548,7 @@ int main(int narg, const char** args) { return std::tuple{1, std::string(), buf.str()}; } } else { - return std::tuple{1, std::string(), std::string("Failed to read file: "sv) + file.first + ".\n"}; + return std::tuple{1, std::string(), "Failed to read file: "s + file.first + ".\n"}; } }); results.push_back(std::move(task)); @@ -588,7 +595,7 @@ int main(int narg, const char** args) { if (lua_pcall(L, 1, 1, 0) != 0) { ret = 2; std::string err = lua_tostring(L, -1); - errs.push_back(std::string("Failed to minify: "sv) + file + '\n' + err + '\n'); + errs.push_back("Failed to minify: "s + file + '\n' + err + '\n'); } else { size_t size = 0; const char* minifiedCodes = lua_tolstring(L, -1, &size); @@ -603,7 +610,7 @@ int main(int narg, const char** args) { } } else { ret = 2; - errs.push_back(std::string("Failed to minify: "sv) + file + '\n'); + errs.push_back("Failed to minify: "s + file + '\n'); } } else { std::cout << msg; diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 05ac5ef..620dfcc 100755 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h @@ -118,16 +118,22 @@ AST_NODE(Local) AST_MEMBER(Local, &item) AST_END(Local, "local"sv) -class Assign_t; +AST_LEAF(const_attrib) +AST_END(const_attrib, "const"sv) + +AST_LEAF(close_attrib) +AST_END(close_attrib, "close"sv) -AST_LEAF(Attrib) -AST_END(Attrib, "attrib"sv) +class simple_table_t; +class TableLit_t; +class Assign_t; AST_NODE(LocalAttrib) - ast_ptr attrib; - ast_ptr nameList; + ast_sel attrib; + ast_ptr sep; + ast_sel_list leftList; ast_ptr assign; - AST_MEMBER(LocalAttrib, &attrib, &nameList, &assign) + AST_MEMBER(LocalAttrib, &attrib, &sep, &leftList, &assign) AST_END(LocalAttrib, "local_attrib"sv) AST_NODE(colon_import_name) @@ -135,9 +141,6 @@ AST_NODE(colon_import_name) AST_MEMBER(colon_import_name, &name) AST_END(colon_import_name, "colon_import_name"sv) -class Exp_t; -class TableLit_t; - AST_LEAF(import_literal_inner) AST_END(import_literal_inner, "import_literal_inner"sv) @@ -147,6 +150,8 @@ AST_NODE(ImportLiteral) AST_MEMBER(ImportLiteral, &sep, &inners) AST_END(ImportLiteral, "import_literal"sv) +class Exp_t; + AST_NODE(ImportFrom) ast_ptr sep; ast_sel_list names; @@ -499,7 +504,6 @@ class String_t; class const_value_t; class ClassDecl_t; class unary_value_t; -class TableLit_t; class FunLit_t; AST_NODE(SimpleValue) diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 7bbf5e9..0d027a0 100755 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -13,6 +13,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include #include "yuescript/yue_parser.h" #include "yuescript/yue_compiler.h" @@ -37,9 +38,6 @@ extern "C" { #endif // YUE_NO_MACRO namespace yue { -using namespace std::string_view_literals; -using namespace std::string_literals; -using namespace parserlib; #define BLOCK_START do { #define BLOCK_END } while (false); @@ -56,7 +54,7 @@ using namespace parserlib; typedef std::list str_list; -const std::string_view version = "0.13.6"sv; +const std::string_view version = "0.14.0"sv; const std::string_view extension = "yue"sv; class YueCompilerImpl { @@ -1266,8 +1264,8 @@ private: std::string getDestrucureDefine(ExpListAssign_t* assignment) { auto info = extractDestructureInfo(assignment, true, false); - if (!info.first.empty()) { - for (const auto& destruct : info.first) { + if (!info.destructures.empty()) { + for (const auto& destruct : info.destructures) { str_list defs; for (const auto& item : destruct.items) { if (!item.targetVar.empty()) { @@ -1319,11 +1317,30 @@ private: return assignment; } + void markDestructureConst(ExpListAssign_t* assignment) { + auto info = extractDestructureInfo(assignment, true, false); + for (auto& destruct : info.destructures) { + for (auto& item : destruct.items) { + if (item.targetVar.empty()) { + throw std::logic_error(_info.errorMessage("can only declare variable as const"sv, item.target)); + } + markVarConst(item.targetVar); + } + } + } + void transformAssignment(ExpListAssign_t* assignment, str_list& out, bool optionalDestruct = false) { checkAssignable(assignment->expList); BLOCK_START auto assign = ast_cast(assignment->action); BREAK_IF(!assign); + if (assignment->expList->exprs.size() < assign->values.size()) { + auto num = assignment->expList->exprs.size(); + _buf << "no more than "sv << num << " right value"sv; + if (num > 1) _buf << 's'; + _buf << " required"sv; + throw std::logic_error(_info.errorMessage(clearBuf(), assign->values.front())); + } auto x = assignment; const auto& exprs = assignment->expList->exprs.objects(); const auto& values = assign->values.objects(); @@ -1554,15 +1571,15 @@ private: } BLOCK_END auto info = extractDestructureInfo(assignment, false, optionalDestruct); - if (info.first.empty()) { + if (info.destructures.empty()) { transformAssignmentCommon(assignment, out); } else { str_list temp; - if (info.second) { - transformAssignmentCommon(info.second, temp); + if (info.assignment) { + transformAssignmentCommon(info.assignment, temp); } auto x = assignment; - for (auto& destruct : info.first) { + for (auto& destruct : info.destructures) { std::list, ast_ptr>> leftPairs; bool extraScope = false; if (destruct.items.size() == 1) { @@ -2030,24 +2047,22 @@ private: return pairs; } - std::pair, ast_ptr> - extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly, bool optional) { + struct DestructureInfo { + std::list destructures; + ast_ptr assignment; + }; + + DestructureInfo extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly, bool optional) { auto x = assignment; std::list destructs; if (!assignment->action.is()) return {destructs, nullptr}; auto exprs = assignment->expList->exprs.objects(); auto values = assignment->action.to()->values.objects(); size_t size = std::max(exprs.size(), values.size()); - ast_list cache; - if (exprs.size() < size) { - auto var = toAst("_"sv, x); - cache.push_back(var); - while (exprs.size() < size) exprs.emplace_back(var); - } - ast_ptr nullNode; + ast_ptr nil; if (values.size() < size) { - nullNode = toAst("nil"sv, x); - while (values.size() < size) values.emplace_back(nullNode); + nil = toAst("nil"sv, x); + while (values.size() < size) values.emplace_back(nil); } using iter = node_container::iterator; std::vector> destructPairs; @@ -2059,11 +2074,11 @@ private: auto value = singleValueFrom(expr); ast_node* destructNode = value->getByPath(); if (destructNode || (destructNode = value->item.as())) { - if (*j != nullNode) { + if (*j != nil) { if (auto ssVal = simpleSingleValueFrom(*j)) { switch (ssVal->value->getId()) { case id(): - throw std::logic_error(_info.errorMessage("can not destructure a const value"sv, ssVal->value)); + throw std::logic_error(_info.errorMessage("can not destructure a constant"sv, ssVal->value)); break; case id(): throw std::logic_error(_info.errorMessage("can not destructure a number"sv, ssVal->value)); @@ -2074,7 +2089,7 @@ private: } } } else { - throw std::logic_error(_info.errorMessage("can not destructure a nil value"sv, destructNode)); + throw std::logic_error(_info.errorMessage("an explicit destructure target required"sv, destructNode)); } destructPairs.push_back({i, j}); auto subDestruct = destructNode->new_ptr(); @@ -2173,7 +2188,7 @@ private: } destruct.items = std::move(pairs); if (!varDefOnly) { - if (*j == nullNode) { + if (*j == nil) { for (auto& item : destruct.items) { item.structure.clear(); } @@ -3104,8 +3119,8 @@ private: } } auto info = extractDestructureInfo(assignment, true, false); - if (!info.first.empty()) { - for (const auto& destruct : info.first) + if (!info.destructures.empty()) { + for (const auto& destruct : info.destructures) for (const auto& item : destruct.items) if (!item.targetVar.empty()) { if (std::isupper(item.targetVar[0]) && capital) { capital->decls.push_back(item.targetVar); @@ -3114,8 +3129,8 @@ private: } } } - if (info.second) { - auto defs = transformAssignDefs(info.second->expList, DefOp::Get); + if (info.assignment) { + auto defs = transformAssignDefs(info.assignment->expList, DefOp::Get); for (const auto& def : defs) { if (std::isupper(def[0]) && capital) { capital->decls.push_back(def); } else if (any) { @@ -3236,6 +3251,49 @@ private: } } + std::optional getOption(std::string_view key) { +#ifndef YUE_NO_MACRO + if (L) { + int top = lua_gettop(L); + DEFER(lua_settop(L, top)); + pushYue("options"sv); // options + lua_pushlstring(L, &key.front(), key.size()); + lua_gettable(L, -2); + if (lua_isstring(L, -1) != 0) { + size_t size = 0; + const char* str = lua_tolstring(L, -1, &size); + return std::string(str, size); + } + } +#endif // YUE_NO_MACRO + auto it = _config.options.find(std::string(key)); + if (it != _config.options.end()) { + return it->second; + } + return std::nullopt; + } + + int getLuaTarget(ast_node* x) { + if (auto target = getOption("target")) { + if (target.value() == "5.1"sv) { + return 501; + } else if (target.value() == "5.2"sv) { + return 502; + } else if (target.value() == "5.3"sv) { + return 503; + } else if (target.value() == "5.4"sv) { + return 504; + } else { + throw std::logic_error(_info.errorMessage("get invalid Lua target \""s + target.value() + "\", should be 5.1, 5.2, 5.3 or 5.4"s, x)); + } + } +#ifndef YUE_NO_MACRO + return LUA_VERSION_NUM; +#else + return 504; +#endif // YUE_NO_MACRO + } + #ifndef YUE_NO_MACRO void passOptions() { if (!_config.options.empty()) { @@ -5898,8 +5956,8 @@ private: auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark); varDefs.insert(varDefs.end(), names.begin(), names.end()); auto info = extractDestructureInfo(assignment, true, false); - if (!info.first.empty()) { - for (const auto& destruct : info.first) + if (!info.destructures.empty()) { + for (const auto& destruct : info.destructures) for (const auto& item : destruct.items) if (!item.targetVar.empty() && addToScope(item.targetVar)) varDefs.push_back(item.targetVar); @@ -6329,8 +6387,8 @@ private: return traversal::Stop; } auto info = extractDestructureInfo(assignment, true, false); - if (!info.first.empty()) { - for (const auto& destruct : info.first) + if (!info.destructures.empty()) { + for (const auto& destruct : info.destructures) for (const auto& item : destruct.items) if (!item.targetVar.empty() && !isDefined(item.targetVar)) return traversal::Stop; @@ -6481,8 +6539,8 @@ private: transformAssignment(assignment, out); str_list names = transformAssignDefs(expList, DefOp::Get); auto info = extractDestructureInfo(assignment, true, false); - if (!info.first.empty()) { - for (const auto& destruct : info.first) + if (!info.destructures.empty()) { + for (const auto& destruct : info.destructures) for (const auto& item : destruct.items) if (!item.targetVar.empty()) names.push_back(item.targetVar); @@ -6848,6 +6906,7 @@ private: temp.push_back(indent() + "end"s + nlr(import)); } out.push_back(join(temp)); + markDestructureConst(assignment); } std::string moduleNameFrom(ImportLiteral_t* literal) { @@ -7013,6 +7072,12 @@ private: assignment->expList.set(assignList); assignment->action.set(assign); transformAssignment(assignment, out); + if (auto var = ast_cast(target)) { + auto moduleName = _parser.toString(var); + markVarConst(moduleName); + } else { + markDestructureConst(assignment); + } } void transformImport(Import_t* import, str_list& out) { @@ -7191,7 +7256,7 @@ private: auto info = extractDestructureInfo(assignment, true, false); transformAssignment(assignment, temp, true); str_list conds; - for (const auto& destruct : info.first) { + for (const auto& destruct : info.destructures) { for (const auto& item : destruct.items) { if (!item.defVal) { transformExp(item.target, conds, ExpUsage::Closure); @@ -7334,23 +7399,84 @@ private: void transformLocalAttrib(LocalAttrib_t* localAttrib, str_list& out) { auto x = localAttrib; - auto attrib = _parser.toString(localAttrib->attrib); - str_list vars; - for (auto name : localAttrib->nameList->names.objects()) { - auto var = _parser.toString(name); - forceAddToScope(var); - vars.push_back(var); + if (x->leftList.size() < x->assign->values.size()) { + throw std::logic_error(_info.errorMessage("number of right values should not be greater than left values"sv, x->assign->values.front())); + } + auto listA = x->new_ptr(); + auto assignA = x->new_ptr(); + auto listB = x->new_ptr(); + auto assignB = x->new_ptr(); + auto i = x->leftList.objects().begin(); + auto ie = x->leftList.objects().end(); + auto j = x->assign->values.objects().begin(); + auto je = x->assign->values.objects().end(); + while (i != ie) { + if (ast_is(*i)) { + listA->names.push_back(*i); + if (j != je) assignA->values.push_back(*j); + } else { + auto item = *i; + auto value = item->new_ptr(); + switch (item->getId()) { + case id(): + value->item.set(item); + break; + case id(): { + auto simpleValue = item->new_ptr(); + simpleValue->value.set(item); + value->item.set(simpleValue); + break; + } + default: YUEE("AST node mismatch", item); break; + } + auto exp = newExp(value, item); + listB->exprs.push_back(exp); + if (j != je) assignB->values.push_back(*j); + } + ++i; + if (j != je) ++j; } - attrib = " <"s + attrib + '>'; - for (auto& var : vars) { - markVarConst(var); - var.append(attrib); + if (!listA->names.empty()) { + str_list vars; + for (auto name : listA->names.objects()) { + auto var = _parser.toString(name); + forceAddToScope(var); + vars.push_back(var); + } + if (getLuaTarget(x) >= 504) { + std::string attrib; + if (localAttrib->attrib.is()) { + attrib = " "s; + } else if (localAttrib->attrib.is()) { + attrib = " "s; + } else { + YUEE("AST node mismatch", localAttrib->attrib); + } + for (auto& var : vars) { + markVarConst(var); + var.append(attrib); + } + } else { + if (localAttrib->attrib.is()) { + throw std::logic_error(_info.errorMessage("close attribute is not available when not targeting Lua 5.4 or higher version"sv, x)); + } + for (auto& var : vars) { + markVarConst(var); + } + } + str_list temp; + for (auto item : assignA->values.objects()) { + transformAssignItem(item, temp); + } + out.push_back(indent() + "local "s + join(vars, ", "sv) + " = "s + join(temp, ", "sv) + nll(x)); } - str_list temp; - for (auto item : localAttrib->assign->values.objects()) { - transformAssignItem(item, temp); + if (!listB->exprs.empty()) { + auto assignment = x->new_ptr(); + assignment->expList.set(listB); + assignment->action.set(assignB); + transformAssignment(assignment, out); + markDestructureConst(assignment); } - out.push_back(indent() + "local "s + join(vars, ", "sv) + " = "s + join(temp, ", "sv) + nll(x)); } void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) { @@ -7372,10 +7498,16 @@ private: } void transformLabel(Label_t* label, str_list& out) { + if (getLuaTarget(label) < 502) { + throw std::logic_error(_info.errorMessage("label statement is not available when not targeting Lua 5.2 or higher version"sv, label)); + } out.push_back(indent() + "::"s + _parser.toString(label->label) + "::"s + nll(label)); } void transformGoto(Goto_t* gotoNode, str_list& out) { + if (getLuaTarget(gotoNode) < 502) { + throw std::logic_error(_info.errorMessage("goto statement is not available when not targeting Lua 5.2 or higher version"sv, gotoNode)); + } out.push_back(indent() + "goto "s + _parser.toString(gotoNode->label) + nll(gotoNode)); } diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 66043d3..94ce550 100755 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -11,25 +11,24 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI namespace pl = parserlib; namespace yue { -using namespace std::string_view_literals; std::unordered_set LuaKeywords = { - "and", "break", "do", "else", "elseif", - "end", "false", "for", "function", "goto", - "if", "in", "local", "nil", "not", - "or", "repeat", "return", "then", "true", - "until", "while" + "and"s, "break"s, "do"s, "else"s, "elseif"s, + "end"s, "false"s, "for"s, "function"s, "goto"s, + "if"s, "in"s, "local"s, "nil"s, "not"s, + "or"s, "repeat"s, "return"s, "then"s, "true"s, + "until"s, "while"s }; std::unordered_set Keywords = { - "and", "break", "do", "else", "elseif", - "end", "false", "for", "function", "goto", - "if", "in", "local", "nil", "not", - "or", "repeat", "return", "then", "true", - "until", "while", // Lua keywords - "as", "class", "continue", "export", "extends", - "from", "global", "import", "macro", "switch", - "try", "unless", "using", "when", "with" // Yue keywords + "and"s, "break"s, "do"s, "else"s, "elseif"s, + "end"s, "false"s, "for"s, "function"s, "goto"s, + "if"s, "in"s, "local"s, "nil"s, "not"s, + "or"s, "repeat"s, "return"s, "then"s, "true"s, + "until"s, "while"s, // Lua keywords + "as"s, "class"s, "continue"s, "export"s, "extends"s, + "from"s, "global"s, "import"s, "macro"s, "switch"s, + "try"s, "unless"s, "using"s, "when"s, "with"s // Yue keywords }; YueParser::YueParser() { @@ -86,7 +85,7 @@ YueParser::YueParser() { if (isValid) { if (st->buffer == st->moduleName) { st->moduleFix++; - st->moduleName = std::string("_module_"sv) + std::to_string(st->moduleFix); + st->moduleName = "_module_"s + std::to_string(st->moduleFix); } } st->buffer.clear(); @@ -179,10 +178,15 @@ YueParser::YueParser() { local_flag = expr('*') | expr('^'); local_values = NameList >> -(sym('=') >> (TableBlock | ExpListLow)); - Attrib = (expr("const") | expr("close")) >> not_(AlphaNum); Local = key("local") >> (Space >> local_flag | local_values); - LocalAttrib = Attrib >> NameList >> Assign; + const_attrib = key("const"); + close_attrib = key("close"); + local_const_item = (Space >> Variable | simple_table | TableLit); + LocalAttrib = ( + const_attrib >> Seperator >> local_const_item >> *(sym(',') >> local_const_item) | + close_attrib >> Seperator >> Space >> Variable >> *(sym(',') >> Space >> Variable) + ) >> Assign; colon_import_name = sym('\\') >> Space >> Variable; ImportName = colon_import_name | Space >> Variable; @@ -754,6 +758,10 @@ std::string ParseInfo::errorMessage(std::string_view msg, const input_range* loc ++it; } auto line = Converter{}.to_bytes(std::wstring(begin, end)); + while (col < static_cast(line.size()) + && (line[col] == ' ' || line[col] == '\t')) { + col++; + } Utils::replace(line, "\t"sv, " "sv); std::ostringstream buf; buf << loc->m_begin.m_line << ": "sv << msg << diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index b71a67c..b363ad7 100755 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h @@ -21,6 +21,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include "yuescript/yue_ast.h" namespace yue { +using namespace std::string_view_literals; +using namespace std::string_literals; using namespace parserlib; struct ParseInfo { @@ -77,7 +79,7 @@ protected: int exportCount = 0; int moduleFix = 0; size_t stringOpen = 0; - std::string moduleName = "_module_0"; + std::string moduleName = "_module_0"s; std::string buffer; std::stack indents; std::stack noDoStack; @@ -189,6 +191,7 @@ private: rule expo_value; rule expo_exp; rule exp_not_tab; + rule local_const_item; rule empty_line_stop; rule Line; rule Shebang; @@ -209,8 +212,9 @@ private: AST_RULE(NameList) AST_RULE(local_flag) AST_RULE(local_values) - AST_RULE(Attrib) AST_RULE(Local) + AST_RULE(const_attrib) + AST_RULE(close_attrib) AST_RULE(LocalAttrib); AST_RULE(colon_import_name) AST_RULE(import_literal_inner) diff --git a/src/yuescript/yuescript.cpp b/src/yuescript/yuescript.cpp index 2e96f16..98e214f 100644 --- a/src/yuescript/yuescript.cpp +++ b/src/yuescript/yuescript.cpp @@ -9,6 +9,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include "yuescript/yue_compiler.h" #include "yuescript/yue_parser.h" +using namespace std::string_literals; + #if defined(YUE_BUILD_AS_DLL) #define YUE_API __declspec(dllexport) #else @@ -25,12 +27,12 @@ static const char yuescriptCodes[] = static void init_yuescript(lua_State* L) { if (luaL_loadbuffer(L, yuescriptCodes, sizeof(yuescriptCodes) / sizeof(yuescriptCodes[0]) - 1, "=(yuescript)") != 0) { - std::string err = std::string("failed to load yuescript module.\n") + lua_tostring(L, -1); + std::string err = "failed to load yuescript module.\n"s + lua_tostring(L, -1); luaL_error(L, err.c_str()); } else { lua_insert(L, -2); if (lua_pcall(L, 1, 0, 0) != 0) { - std::string err = std::string("failed to init yuescript module.\n") + lua_tostring(L, -1); + std::string err = "failed to init yuescript module.\n"s + lua_tostring(L, -1); luaL_error(L, err.c_str()); } } @@ -41,10 +43,10 @@ static const char stpCodes[] = static int init_stacktraceplus(lua_State* L) { if (luaL_loadbuffer(L, stpCodes, sizeof(stpCodes) / sizeof(stpCodes[0]) - 1, "=(stacktraceplus)") != 0) { - std::string err = std::string("failed to load stacktraceplus module.\n") + lua_tostring(L, -1); + std::string err = "failed to load stacktraceplus module.\n"s + lua_tostring(L, -1); luaL_error(L, err.c_str()); } else if (lua_pcall(L, 0, 1, 0) != 0) { - std::string err = std::string("failed to init stacktraceplus module.\n") + lua_tostring(L, -1); + std::string err = "failed to init stacktraceplus module.\n"s + lua_tostring(L, -1); luaL_error(L, err.c_str()); } return 1; -- cgit v1.2.3-55-g6feb