diff options
author | Li Jin <dragon-fly@qq.com> | 2025-05-28 18:20:16 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2025-05-28 18:20:16 +0800 |
commit | 5604bbbb80bfcedb4a9085b90864e221f8104b33 (patch) | |
tree | 8828cddb1b0fe0ca734d6209507bdbda3133f48d /src | |
parent | 87267ca9e93606b70bdc0397349b176b8d142514 (diff) | |
download | yuescript-5604bbbb80bfcedb4a9085b90864e221f8104b33.tar.gz yuescript-5604bbbb80bfcedb4a9085b90864e221f8104b33.tar.bz2 yuescript-5604bbbb80bfcedb4a9085b90864e221f8104b33.zip |
Added `try!` syntax.
Diffstat (limited to 'src')
-rw-r--r-- | src/yuescript/yue_ast.cpp | 10 | ||||
-rw-r--r-- | src/yuescript/yue_ast.h | 6 | ||||
-rw-r--r-- | src/yuescript/yue_compiler.cpp | 155 | ||||
-rw-r--r-- | src/yuescript/yue_compiler.h | 1 | ||||
-rw-r--r-- | src/yuescript/yue_parser.cpp | 25 | ||||
-rw-r--r-- | src/yuescript/yue_parser.h | 13 | ||||
-rw-r--r-- | src/yuescript/yuescript.cpp | 15 |
7 files changed, 163 insertions, 62 deletions
diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp index 9d68161..be10859 100644 --- a/src/yuescript/yue_ast.cpp +++ b/src/yuescript/yue_ast.cpp | |||
@@ -609,13 +609,19 @@ std::string CatchBlock_t::to_string(void* ud) const { | |||
609 | info->popScope(); | 609 | info->popScope(); |
610 | return line + '\n' + blockStr; | 610 | return line + '\n' + blockStr; |
611 | } | 611 | } |
612 | std::string Omit_t::to_string(void*) const { | ||
613 | return "!"s; | ||
614 | } | ||
612 | std::string Try_t::to_string(void* ud) const { | 615 | std::string Try_t::to_string(void* ud) const { |
613 | auto info = reinterpret_cast<YueFormat*>(ud); | 616 | auto info = reinterpret_cast<YueFormat*>(ud); |
614 | str_list temp; | 617 | str_list temp; |
618 | temp.emplace_back("try"s); | ||
619 | if (omit) { | ||
620 | temp.back() += '!'; | ||
621 | } | ||
615 | if (func.is<Exp_t>()) { | 622 | if (func.is<Exp_t>()) { |
616 | temp.emplace_back("try "s + func->to_string(ud)); | 623 | temp.back() += (" "s + func->to_string(ud)); |
617 | } else { | 624 | } else { |
618 | temp.emplace_back("try"s); | ||
619 | info->pushScope(); | 625 | info->pushScope(); |
620 | temp.emplace_back(func->to_string(ud)); | 626 | temp.emplace_back(func->to_string(ud)); |
621 | if (temp.back().empty()) { | 627 | if (temp.back().empty()) { |
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index d3e6368..393f374 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h | |||
@@ -383,10 +383,14 @@ AST_NODE(CatchBlock) | |||
383 | AST_MEMBER(CatchBlock, &err, &block) | 383 | AST_MEMBER(CatchBlock, &err, &block) |
384 | AST_END(CatchBlock) | 384 | AST_END(CatchBlock) |
385 | 385 | ||
386 | AST_LEAF(Omit) | ||
387 | AST_END(Omit) | ||
388 | |||
386 | AST_NODE(Try) | 389 | AST_NODE(Try) |
390 | ast_ptr<false, Omit_t> omit; | ||
387 | ast_sel<true, Block_t, Exp_t> func; | 391 | ast_sel<true, Block_t, Exp_t> func; |
388 | ast_ptr<false, CatchBlock_t> catchBlock; | 392 | ast_ptr<false, CatchBlock_t> catchBlock; |
389 | AST_MEMBER(Try, &func, &catchBlock) | 393 | AST_MEMBER(Try, &omit, &func, &catchBlock) |
390 | AST_END(Try) | 394 | AST_END(Try) |
391 | 395 | ||
392 | AST_NODE(Comprehension) | 396 | AST_NODE(Comprehension) |
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 2312025..35745f2 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
@@ -78,7 +78,7 @@ static std::unordered_set<std::string> Metamethods = { | |||
78 | "close"s // Lua 5.4 | 78 | "close"s // Lua 5.4 |
79 | }; | 79 | }; |
80 | 80 | ||
81 | const std::string_view version = "0.28.5"sv; | 81 | const std::string_view version = "0.28.6"sv; |
82 | const std::string_view extension = "yue"sv; | 82 | const std::string_view extension = "yue"sv; |
83 | 83 | ||
84 | class CompileError : public std::logic_error { | 84 | class CompileError : public std::logic_error { |
@@ -165,12 +165,12 @@ public: | |||
165 | double compileTime = 0.0; | 165 | double compileTime = 0.0; |
166 | if (config.profiling) { | 166 | if (config.profiling) { |
167 | auto start = std::chrono::high_resolution_clock::now(); | 167 | auto start = std::chrono::high_resolution_clock::now(); |
168 | _info = _parser.parse<File_t>(codes); | 168 | _info = _parser.parse<File_t>(codes, config.lax); |
169 | auto stop = std::chrono::high_resolution_clock::now(); | 169 | auto stop = std::chrono::high_resolution_clock::now(); |
170 | std::chrono::duration<double> diff = stop - start; | 170 | std::chrono::duration<double> diff = stop - start; |
171 | parseTime = diff.count(); | 171 | parseTime = diff.count(); |
172 | } else { | 172 | } else { |
173 | _info = _parser.parse<File_t>(codes); | 173 | _info = _parser.parse<File_t>(codes, config.lax); |
174 | } | 174 | } |
175 | std::unique_ptr<GlobalVars> globals; | 175 | std::unique_ptr<GlobalVars> globals; |
176 | std::unique_ptr<Options> options; | 176 | std::unique_ptr<Options> options; |
@@ -1258,7 +1258,7 @@ private: | |||
1258 | 1258 | ||
1259 | template <class T> | 1259 | template <class T> |
1260 | ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) { | 1260 | ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) { |
1261 | auto res = _parser.parse<T>(std::string(codes)); | 1261 | auto res = _parser.parse<T>(std::string(codes), false); |
1262 | if (res.error) { | 1262 | if (res.error) { |
1263 | throw CompileError(res.error.value().msg, parent); | 1263 | throw CompileError(res.error.value().msg, parent); |
1264 | } | 1264 | } |
@@ -2330,6 +2330,17 @@ private: | |||
2330 | out.back().insert(0, preDefine); | 2330 | out.back().insert(0, preDefine); |
2331 | return false; | 2331 | return false; |
2332 | } | 2332 | } |
2333 | case id<Try_t>(): { | ||
2334 | auto tryNode = static_cast<Try_t*>(value); | ||
2335 | if (tryNode->omit) { | ||
2336 | auto assignList = assignment->expList.get(); | ||
2337 | std::string preDefine = getPreDefineLine(assignment); | ||
2338 | transformTry(tryNode, out, ExpUsage::Assignment, assignList); | ||
2339 | out.back().insert(0, preDefine); | ||
2340 | return false; | ||
2341 | } | ||
2342 | break; | ||
2343 | } | ||
2333 | case id<Switch_t>(): { | 2344 | case id<Switch_t>(): { |
2334 | auto switchNode = static_cast<Switch_t*>(value); | 2345 | auto switchNode = static_cast<Switch_t*>(value); |
2335 | auto assignList = assignment->expList.get(); | 2346 | auto assignList = assignment->expList.get(); |
@@ -4272,12 +4283,22 @@ private: | |||
4272 | 4283 | ||
4273 | std::optional<std::pair<std::string, str_list>> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) { | 4284 | std::optional<std::pair<std::string, str_list>> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) { |
4274 | if (checkUpValueFuncAvailable(exp)) { | 4285 | if (checkUpValueFuncAvailable(exp)) { |
4286 | auto block = exp->new_ptr<Block_t>(); | ||
4287 | if (auto sVal = simpleSingleValueFrom(exp)) { | ||
4288 | if (auto doNode = sVal->value.as<Do_t>()) { | ||
4289 | if (auto blk = doNode->body->content.as<Block_t>()) { | ||
4290 | block->statements.dup(blk->statements); | ||
4291 | } else { | ||
4292 | block->statements.push_back(doNode->body->content.to<Statement_t>()); | ||
4293 | } | ||
4294 | return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite); | ||
4295 | } | ||
4296 | } | ||
4275 | auto returnNode = exp->new_ptr<Return_t>(); | 4297 | auto returnNode = exp->new_ptr<Return_t>(); |
4276 | returnNode->explicitReturn = false; | 4298 | returnNode->explicitReturn = false; |
4277 | auto returnList = exp->new_ptr<ExpListLow_t>(); | 4299 | auto returnList = exp->new_ptr<ExpListLow_t>(); |
4278 | returnList->exprs.push_back(exp); | 4300 | returnList->exprs.push_back(exp); |
4279 | returnNode->valueList.set(returnList); | 4301 | returnNode->valueList.set(returnList); |
4280 | auto block = exp->new_ptr<Block_t>(); | ||
4281 | auto stmt = exp->new_ptr<Statement_t>(); | 4302 | auto stmt = exp->new_ptr<Statement_t>(); |
4282 | stmt->content.set(returnNode); | 4303 | stmt->content.set(returnNode); |
4283 | block->statements.push_back(stmt); | 4304 | block->statements.push_back(stmt); |
@@ -4799,11 +4820,7 @@ private: | |||
4799 | auto newBody = x->new_ptr<Body_t>(); | 4820 | auto newBody = x->new_ptr<Body_t>(); |
4800 | newBody->content.set(followingBlock); | 4821 | newBody->content.set(followingBlock); |
4801 | { | 4822 | { |
4802 | auto doNode = x->new_ptr<Do_t>(); | 4823 | if (auto result = upValueFuncFromBlock(followingBlock.get(), &argNames, false, true)) { |
4803 | doNode->body.set(newBody); | ||
4804 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
4805 | simpleValue->value.set(doNode); | ||
4806 | if (auto result = upValueFuncFromExp(newExp(simpleValue, x), &argNames, true)) { | ||
4807 | auto [funcName, args] = std::move(*result); | 4824 | auto [funcName, args] = std::move(*result); |
4808 | str_list finalArgs; | 4825 | str_list finalArgs; |
4809 | for (const auto& arg : args) { | 4826 | for (const auto& arg : args) { |
@@ -4811,9 +4828,13 @@ private: | |||
4811 | finalArgs.push_back(arg); | 4828 | finalArgs.push_back(arg); |
4812 | } | 4829 | } |
4813 | } | 4830 | } |
4814 | newBlock->statements.push_back(toAst<Statement_t>(funcName + ' ' + join(finalArgs, ","sv), x)); | 4831 | newBlock->statements.push_back(toAst<Statement_t>(funcName + ' ' + (finalArgs.empty() ? "nil"s : join(finalArgs, ","sv)), x)); |
4815 | auto sVal = singleValueFrom(static_cast<Statement_t*>(newBlock->statements.back())->content.to<ExpListAssign_t>()->expList); | 4832 | auto sVal = singleValueFrom(static_cast<Statement_t*>(newBlock->statements.back())->content.to<ExpListAssign_t>()->expList); |
4816 | ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back())->args.dup(newInvoke->args); | 4833 | auto invokArgs = ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back()); |
4834 | if (finalArgs.empty()) { | ||
4835 | invokArgs->args.clear(); | ||
4836 | } | ||
4837 | invokArgs->args.dup(newInvoke->args); | ||
4817 | transformBlock(newBlock, out, usage, assignList, isRoot); | 4838 | transformBlock(newBlock, out, usage, assignList, isRoot); |
4818 | return; | 4839 | return; |
4819 | } | 4840 | } |
@@ -5093,36 +5114,45 @@ private: | |||
5093 | if (!nodes.empty()) { | 5114 | if (!nodes.empty()) { |
5094 | str_list temp; | 5115 | str_list temp; |
5095 | for (auto node : nodes) { | 5116 | for (auto node : nodes) { |
5096 | currentScope().lastStatement = (node == nodes.back()) && currentScope().mode == GlobalMode::None; | 5117 | auto transformNode = [&]() { |
5097 | transformStatement(static_cast<Statement_t*>(node), temp); | 5118 | currentScope().lastStatement = (node == nodes.back()) && currentScope().mode == GlobalMode::None; |
5098 | if (isRoot && !_rootDefs.empty()) { | 5119 | transformStatement(static_cast<Statement_t*>(node), temp); |
5099 | auto last = std::move(temp.back()); | 5120 | if (isRoot && !_rootDefs.empty()) { |
5100 | temp.pop_back(); | 5121 | auto last = std::move(temp.back()); |
5101 | temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end()); | 5122 | temp.pop_back(); |
5102 | _rootDefs.clear(); | 5123 | temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end()); |
5103 | temp.push_back(std::move(last)); | 5124 | _rootDefs.clear(); |
5104 | } | 5125 | temp.push_back(std::move(last)); |
5105 | if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) { | 5126 | } |
5106 | auto rit = ++temp.rbegin(); | 5127 | if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) { |
5107 | if (rit != temp.rend() && !rit->empty()) { | 5128 | auto rit = ++temp.rbegin(); |
5108 | auto index = std::string::npos; | 5129 | if (rit != temp.rend() && !rit->empty()) { |
5109 | if (_config.reserveLineNumber) { | 5130 | auto index = std::string::npos; |
5110 | index = rit->rfind(" -- "sv); | 5131 | if (_config.reserveLineNumber) { |
5111 | } else { | 5132 | index = rit->rfind(" -- "sv); |
5112 | index = rit->find_last_not_of('\n'); | 5133 | } else { |
5113 | if (index != std::string::npos) index++; | 5134 | index = rit->find_last_not_of('\n'); |
5114 | } | 5135 | if (index != std::string::npos) index++; |
5115 | if (index != std::string::npos) { | ||
5116 | auto ending = rit->substr(0, index); | ||
5117 | auto ind = ending.find_last_of(" \t\n"sv); | ||
5118 | if (ind != std::string::npos) { | ||
5119 | ending = ending.substr(ind + 1); | ||
5120 | } | 5136 | } |
5121 | if (LuaKeywords.find(ending) == LuaKeywords.end()) { | 5137 | if (index != std::string::npos) { |
5122 | rit->insert(index, ";"sv); | 5138 | auto ending = rit->substr(0, index); |
5139 | auto ind = ending.find_last_of(" \t\n"sv); | ||
5140 | if (ind != std::string::npos) { | ||
5141 | ending = ending.substr(ind + 1); | ||
5142 | } | ||
5143 | if (LuaKeywords.find(ending) == LuaKeywords.end()) { | ||
5144 | rit->insert(index, ";"sv); | ||
5145 | } | ||
5123 | } | 5146 | } |
5124 | } | 5147 | } |
5125 | } | 5148 | } |
5149 | }; | ||
5150 | if (_config.lax) { | ||
5151 | try { | ||
5152 | transformNode(); | ||
5153 | } catch (const CompileError&) { } | ||
5154 | } else { | ||
5155 | transformNode(); | ||
5126 | } | 5156 | } |
5127 | } | 5157 | } |
5128 | out.push_back(join(temp)); | 5158 | out.push_back(join(temp)); |
@@ -6193,7 +6223,7 @@ private: | |||
6193 | case id<ColonChainItem_t>(): | 6223 | case id<ColonChainItem_t>(): |
6194 | case id<Exp_t>(): | 6224 | case id<Exp_t>(): |
6195 | if (_withVars.empty()) { | 6225 | if (_withVars.empty()) { |
6196 | throw CompileError("short dot/colon and indexing syntax must be called within a with block"sv, x); | 6226 | throw CompileError("short dot/colon/indexing syntax must be called within a with block"sv, x); |
6197 | } else { | 6227 | } else { |
6198 | temp.push_back(_withVars.top()); | 6228 | temp.push_back(_withVars.top()); |
6199 | } | 6229 | } |
@@ -6714,14 +6744,14 @@ private: | |||
6714 | } else { | 6744 | } else { |
6715 | if (!codes.empty()) { | 6745 | if (!codes.empty()) { |
6716 | if (isBlock) { | 6746 | if (isBlock) { |
6717 | info = _parser.parse<BlockEnd_t>(codes); | 6747 | info = _parser.parse<BlockEnd_t>(codes, false); |
6718 | if (info.error) { | 6748 | if (info.error) { |
6719 | throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x); | 6749 | throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x); |
6720 | } | 6750 | } |
6721 | } else { | 6751 | } else { |
6722 | info = _parser.parse<Exp_t>(codes); | 6752 | info = _parser.parse<Exp_t>(codes, false); |
6723 | if (!info.node && allowBlockMacroReturn) { | 6753 | if (!info.node && allowBlockMacroReturn) { |
6724 | info = _parser.parse<BlockEnd_t>(codes); | 6754 | info = _parser.parse<BlockEnd_t>(codes, false); |
6725 | if (info.error) { | 6755 | if (info.error) { |
6726 | throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x); | 6756 | throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x); |
6727 | } | 6757 | } |
@@ -10023,8 +10053,47 @@ private: | |||
10023 | out.push_back(join(temp)); | 10053 | out.push_back(join(temp)); |
10024 | } | 10054 | } |
10025 | 10055 | ||
10026 | void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage) { | 10056 | void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { |
10027 | auto x = tryNode; | 10057 | auto x = tryNode; |
10058 | if (tryNode->omit && usage == ExpUsage::Assignment) { | ||
10059 | str_list rets; | ||
10060 | pushScope(); | ||
10061 | auto okVar = getUnusedName("_ok_"sv); | ||
10062 | for (size_t i = 0; i < assignList->exprs.size(); i++) { | ||
10063 | auto retVar = getUnusedName("_ret_"sv); | ||
10064 | rets.emplace_back(retVar); | ||
10065 | addToScope(retVar); | ||
10066 | } | ||
10067 | popScope(); | ||
10068 | auto varList = join(rets, ","sv); | ||
10069 | auto ifNode = toAst<If_t>("if "s + okVar + ',' + varList + ":=try nil then "s + varList, x); | ||
10070 | auto exp = ast_to<IfCond_t>(ifNode->nodes.front())->assignment->assign->values.front(); | ||
10071 | auto sVal = simpleSingleValueFrom(exp); | ||
10072 | auto newTry = sVal->value.to<Try_t>(); | ||
10073 | newTry->func.set(tryNode->func); | ||
10074 | newTry->catchBlock.set(tryNode->catchBlock); | ||
10075 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
10076 | assignment->expList.set(assignList); | ||
10077 | auto assign = x->new_ptr<Assign_t>(); | ||
10078 | assign->values.push_back(ifNode); | ||
10079 | assignment->action.set(assign); | ||
10080 | transformAssignment(assignment, out); | ||
10081 | return; | ||
10082 | } | ||
10083 | if (tryNode->omit && usage != ExpUsage::Common) { | ||
10084 | auto okVar = getUnusedName("_ok_"sv); | ||
10085 | auto code = "do\n\t"s + okVar + ", ... = try nil\n\t... if "s + okVar; | ||
10086 | auto doNode = toAst<Do_t>(code, x); | ||
10087 | auto block = doNode->body->content.to<Block_t>(); | ||
10088 | auto asmt = static_cast<Statement_t*>(block->statements.front())->content.to<ExpListAssign_t>(); | ||
10089 | auto assign = asmt->action.to<Assign_t>(); | ||
10090 | auto sVal = simpleSingleValueFrom(assign->values.back()); | ||
10091 | auto newTry = sVal->value.to<Try_t>(); | ||
10092 | newTry->func.set(tryNode->func); | ||
10093 | newTry->catchBlock.set(tryNode->catchBlock); | ||
10094 | transformDo(doNode, out, usage); | ||
10095 | return; | ||
10096 | } | ||
10028 | ast_ptr<true, Exp_t> errHandler; | 10097 | ast_ptr<true, Exp_t> errHandler; |
10029 | if (tryNode->catchBlock) { | 10098 | if (tryNode->catchBlock) { |
10030 | auto catchBlock = tryNode->catchBlock.get(); | 10099 | auto catchBlock = tryNode->catchBlock.get(); |
diff --git a/src/yuescript/yue_compiler.h b/src/yuescript/yue_compiler.h index d352636..aff5978 100644 --- a/src/yuescript/yue_compiler.h +++ b/src/yuescript/yue_compiler.h | |||
@@ -31,6 +31,7 @@ struct YueConfig { | |||
31 | bool reserveLineNumber = true; | 31 | bool reserveLineNumber = true; |
32 | bool useSpaceOverTab = false; | 32 | bool useSpaceOverTab = false; |
33 | bool reserveComment = false; | 33 | bool reserveComment = false; |
34 | bool lax = false; | ||
34 | // internal options | 35 | // internal options |
35 | bool exporting = false; | 36 | bool exporting = false; |
36 | bool profiling = false; | 37 | bool profiling = false; |
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index e5bdc26..2b0aea8 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp | |||
@@ -332,7 +332,7 @@ YueParser::YueParser() { | |||
332 | Exp; | 332 | Exp; |
333 | import_tab_list = import_tab_item >> *(space >> ',' >> space >> import_tab_item); | 333 | import_tab_list = import_tab_item >> *(space >> ',' >> space >> import_tab_item); |
334 | import_tab_line = ( | 334 | import_tab_line = ( |
335 | push_indent_match >> (space >> import_tab_list >> pop_indent | pop_indent) | 335 | push_indent_match >> ensure(space >> import_tab_list, pop_indent) |
336 | ) | space; | 336 | ) | space; |
337 | import_tab_lines = space_break >> import_tab_line >> *(-(space >> ',') >> space_break >> import_tab_line) >> -(space >> ','); | 337 | import_tab_lines = space_break >> import_tab_line >> *(-(space >> ',') >> space_break >> import_tab_line) >> -(space >> ','); |
338 | import_tab_key_value = key_value | ':' >> MacroName | MacroNamePair | ImportAllMacro; | 338 | import_tab_key_value = key_value | ':' >> MacroName | MacroNamePair | ImportAllMacro; |
@@ -501,8 +501,9 @@ YueParser::YueParser() { | |||
501 | return true; | 501 | return true; |
502 | }); | 502 | }); |
503 | 503 | ||
504 | Omit = expr('!'); | ||
504 | CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> Variable >> space >> in_block; | 505 | CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> Variable >> space >> in_block; |
505 | Try = key("try") >> space >> (in_block | Exp) >> -CatchBlock; | 506 | Try = key("try") >> -Omit >> space >> (in_block | Exp) >> -CatchBlock; |
506 | 507 | ||
507 | list_value = | 508 | list_value = |
508 | and_( | 509 | and_( |
@@ -667,7 +668,7 @@ YueParser::YueParser() { | |||
667 | fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp); | 668 | fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp); |
668 | 669 | ||
669 | fn_args_lit_line = ( | 670 | fn_args_lit_line = ( |
670 | push_indent_match >> (space >> fn_args_value_list >> pop_indent | pop_indent) | 671 | push_indent_match >> ensure(space >> fn_args_value_list, pop_indent) |
671 | ) | ( | 672 | ) | ( |
672 | space | 673 | space |
673 | ); | 674 | ); |
@@ -875,7 +876,7 @@ YueParser::YueParser() { | |||
875 | fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef); | 876 | fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef); |
876 | 877 | ||
877 | fn_arg_def_lit_line = ( | 878 | fn_arg_def_lit_line = ( |
878 | push_indent_match >> (space >> fn_arg_def_list >> pop_indent | pop_indent) | 879 | push_indent_match >> ensure(space >> fn_arg_def_list, pop_indent) |
879 | ) | ( | 880 | ) | ( |
880 | space | 881 | space |
881 | ); | 882 | ); |
@@ -1030,11 +1031,16 @@ YueParser::YueParser() { | |||
1030 | empty_line_break | | 1031 | empty_line_break | |
1031 | advance_match >> ensure(space >> (indentation_error | Statement), pop_indent) | 1032 | advance_match >> ensure(space >> (indentation_error | Statement), pop_indent) |
1032 | ); | 1033 | ); |
1033 | Block = Seperator >> line >> *(+line_break >> line); | 1034 | Block = Seperator >> (pl::user(true_(), [](const item_t& item) { |
1035 | State* st = reinterpret_cast<State*>(item.user_data); | ||
1036 | return st->lax; | ||
1037 | }) >> lax_line >> *(+line_break >> lax_line) | line >> *(+line_break >> line)); | ||
1034 | 1038 | ||
1035 | shebang = "#!" >> *(not_(stop) >> any_char); | 1039 | shebang = "#!" >> *(not_(stop) >> any_char); |
1036 | BlockEnd = Block >> white >> stop; | 1040 | BlockEnd = Block >> white >> stop; |
1037 | File = -shebang >> -Block >> white >> stop; | 1041 | File = -shebang >> -Block >> white >> stop; |
1042 | |||
1043 | lax_line = advance_match >> ensure(*(not_(stop) >> any()), pop_indent) | line >> and_(stop) | check_indent_match >> *(not_(stop) >> any()); | ||
1038 | } | 1044 | } |
1039 | // clang-format on | 1045 | // clang-format on |
1040 | 1046 | ||
@@ -1064,7 +1070,7 @@ bool YueParser::startWith(std::string_view codes, rule& r) { | |||
1064 | return true; | 1070 | return true; |
1065 | } | 1071 | } |
1066 | 1072 | ||
1067 | ParseInfo YueParser::parse(std::string_view codes, rule& r) { | 1073 | ParseInfo YueParser::parse(std::string_view codes, rule& r, bool lax) { |
1068 | ParseInfo res; | 1074 | ParseInfo res; |
1069 | if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) { | 1075 | if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) { |
1070 | codes = codes.substr(3); | 1076 | codes = codes.substr(3); |
@@ -1082,6 +1088,7 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) { | |||
1082 | error_list errors; | 1088 | error_list errors; |
1083 | try { | 1089 | try { |
1084 | State state; | 1090 | State state; |
1091 | state.lax = lax; | ||
1085 | res.node.set(::yue::parse(*(res.codes), r, errors, &state)); | 1092 | res.node.set(::yue::parse(*(res.codes), r, errors, &state)); |
1086 | if (state.exportCount > 0) { | 1093 | if (state.exportCount > 0) { |
1087 | int index = 0; | 1094 | int index = 0; |
@@ -1119,10 +1126,10 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) { | |||
1119 | return res; | 1126 | return res; |
1120 | } | 1127 | } |
1121 | 1128 | ||
1122 | ParseInfo YueParser::parse(std::string_view astName, std::string_view codes) { | 1129 | ParseInfo YueParser::parse(std::string_view astName, std::string_view codes, bool lax) { |
1123 | auto it = _rules.find(astName); | 1130 | auto it = _rules.find(astName); |
1124 | if (it != _rules.end()) { | 1131 | if (it != _rules.end()) { |
1125 | return parse(codes, *it->second); | 1132 | return parse(codes, *it->second, lax); |
1126 | } | 1133 | } |
1127 | return {}; | 1134 | return {}; |
1128 | } | 1135 | } |
@@ -1131,7 +1138,7 @@ bool YueParser::match(std::string_view astName, std::string_view codes) { | |||
1131 | auto it = _rules.find(astName); | 1138 | auto it = _rules.find(astName); |
1132 | if (it != _rules.end()) { | 1139 | if (it != _rules.end()) { |
1133 | auto rEnd = rule(*it->second >> eof()); | 1140 | auto rEnd = rule(*it->second >> eof()); |
1134 | return parse(codes, rEnd).node; | 1141 | return parse(codes, rEnd, false).node; |
1135 | } | 1142 | } |
1136 | return false; | 1143 | return false; |
1137 | } | 1144 | } |
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 773bdbe..99f3d45 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h | |||
@@ -74,16 +74,16 @@ extern std::unordered_set<std::string> Keywords; | |||
74 | class YueParser { | 74 | class YueParser { |
75 | public: | 75 | public: |
76 | template <class AST> | 76 | template <class AST> |
77 | ParseInfo parse(std::string_view codes) { | 77 | ParseInfo parse(std::string_view codes, bool lax) { |
78 | return parse(codes, getRule<AST>()); | 78 | return parse(codes, getRule<AST>(), lax); |
79 | } | 79 | } |
80 | 80 | ||
81 | ParseInfo parse(std::string_view astName, std::string_view codes); | 81 | ParseInfo parse(std::string_view astName, std::string_view codes, bool lax); |
82 | 82 | ||
83 | template <class AST> | 83 | template <class AST> |
84 | bool match(std::string_view codes) { | 84 | bool match(std::string_view codes) { |
85 | auto rEnd = rule(getRule<AST>() >> eof()); | 85 | auto rEnd = rule(getRule<AST>() >> eof()); |
86 | return parse(codes, rEnd).node; | 86 | return parse(codes, rEnd, false).node; |
87 | } | 87 | } |
88 | 88 | ||
89 | bool match(std::string_view astName, std::string_view codes); | 89 | bool match(std::string_view astName, std::string_view codes); |
@@ -102,13 +102,14 @@ public: | |||
102 | 102 | ||
103 | protected: | 103 | protected: |
104 | YueParser(); | 104 | YueParser(); |
105 | ParseInfo parse(std::string_view codes, rule& r); | 105 | ParseInfo parse(std::string_view codes, rule& r, bool lax); |
106 | bool startWith(std::string_view codes, rule& r); | 106 | bool startWith(std::string_view codes, rule& r); |
107 | 107 | ||
108 | struct State { | 108 | struct State { |
109 | State() { | 109 | State() { |
110 | indents.push(0); | 110 | indents.push(0); |
111 | } | 111 | } |
112 | bool lax = false; | ||
112 | bool exportDefault = false; | 113 | bool exportDefault = false; |
113 | bool exportMacro = false; | 114 | bool exportMacro = false; |
114 | bool exportMetatable = false; | 115 | bool exportMetatable = false; |
@@ -287,6 +288,7 @@ private: | |||
287 | NONE_AST_RULE(yue_line_comment); | 288 | NONE_AST_RULE(yue_line_comment); |
288 | NONE_AST_RULE(line); | 289 | NONE_AST_RULE(line); |
289 | NONE_AST_RULE(shebang); | 290 | NONE_AST_RULE(shebang); |
291 | NONE_AST_RULE(lax_line); | ||
290 | 292 | ||
291 | AST_RULE(Num); | 293 | AST_RULE(Num); |
292 | AST_RULE(Name); | 294 | AST_RULE(Name); |
@@ -345,6 +347,7 @@ private: | |||
345 | AST_RULE(ForEach); | 347 | AST_RULE(ForEach); |
346 | AST_RULE(Do); | 348 | AST_RULE(Do); |
347 | AST_RULE(CatchBlock); | 349 | AST_RULE(CatchBlock); |
350 | AST_RULE(Omit); | ||
348 | AST_RULE(Try); | 351 | AST_RULE(Try); |
349 | AST_RULE(Comprehension); | 352 | AST_RULE(Comprehension); |
350 | AST_RULE(CompValue); | 353 | AST_RULE(CompValue); |
diff --git a/src/yuescript/yuescript.cpp b/src/yuescript/yuescript.cpp index 7e8e8b7..aa19b70 100644 --- a/src/yuescript/yuescript.cpp +++ b/src/yuescript/yuescript.cpp | |||
@@ -93,6 +93,12 @@ static void get_config(lua_State* L, yue::YueConfig& config) { | |||
93 | config.useSpaceOverTab = lua_toboolean(L, -1) != 0; | 93 | config.useSpaceOverTab = lua_toboolean(L, -1) != 0; |
94 | } | 94 | } |
95 | lua_pop(L, 1); | 95 | lua_pop(L, 1); |
96 | lua_pushliteral(L, "lax"); | ||
97 | lua_gettable(L, -2); | ||
98 | if (lua_isboolean(L, -1) != 0) { | ||
99 | config.lax = lua_toboolean(L, -1) != 0; | ||
100 | } | ||
101 | lua_pop(L, 1); | ||
96 | lua_pushliteral(L, "options"); | 102 | lua_pushliteral(L, "options"); |
97 | lua_gettable(L, -2); | 103 | lua_gettable(L, -2); |
98 | if (lua_istable(L, -1) != 0) { | 104 | if (lua_istable(L, -1) != 0) { |
@@ -180,7 +186,7 @@ static int yueformat(lua_State* L) { | |||
180 | tabSize = static_cast<int>(luaL_checkinteger(L, 2)); | 186 | tabSize = static_cast<int>(luaL_checkinteger(L, 2)); |
181 | } | 187 | } |
182 | std::string_view codes(input, len); | 188 | std::string_view codes(input, len); |
183 | auto info = yue::YueParser::shared().parse<yue::File_t>(codes); | 189 | auto info = yue::YueParser::shared().parse<yue::File_t>(codes, false); |
184 | if (info.error) { | 190 | if (info.error) { |
185 | const auto& error = info.error.value(); | 191 | const auto& error = info.error.value(); |
186 | if (!info.codes) { | 192 | if (!info.codes) { |
@@ -282,8 +288,13 @@ static int yuetoast(lua_State* L) { | |||
282 | ruleName = {name, nameSize}; | 288 | ruleName = {name, nameSize}; |
283 | } | 289 | } |
284 | } | 290 | } |
291 | bool lax = false; | ||
292 | if (!lua_isnoneornil(L, 4)) { | ||
293 | luaL_checktype(L, 4, LUA_TBOOLEAN); | ||
294 | lax = lua_toboolean(L, 4) != 0; | ||
295 | } | ||
285 | auto& yueParser = yue::YueParser::shared(); | 296 | auto& yueParser = yue::YueParser::shared(); |
286 | auto info = ruleName.empty() ? yueParser.parse<yue::File_t>({input, size}) : yueParser.parse(ruleName, {input, size}); | 297 | auto info = ruleName.empty() ? yueParser.parse<yue::File_t>({input, size}, lax) : yueParser.parse(ruleName, {input, size}, lax); |
287 | if (!info.error) { | 298 | if (!info.error) { |
288 | lua_createtable(L, 0, 0); | 299 | lua_createtable(L, 0, 0); |
289 | int tableIndex = lua_gettop(L); | 300 | int tableIndex = lua_gettop(L); |