diff options
author | Li Jin <dragon-fly@qq.com> | 2022-02-21 14:07:07 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2022-02-21 14:07:07 +0800 |
commit | 7167828a9d873156ad208d161cd1a2dc8ab78523 (patch) | |
tree | 3be64f80b735e792e4bfb35dc864f995530305b6 | |
parent | 6beed7cdbad4577e7dd29c48adcc064a5dab47ba (diff) | |
download | yuescript-7167828a9d873156ad208d161cd1a2dc8ab78523.tar.gz yuescript-7167828a9d873156ad208d161cd1a2dc8ab78523.tar.bz2 yuescript-7167828a9d873156ad208d161cd1a2dc8ab78523.zip |
fixing issue #80.
-rw-r--r-- | spec/inputs/try-catch.yue | 30 | ||||
-rw-r--r-- | spec/outputs/try-catch.lua | 27 | ||||
-rw-r--r-- | src/yuescript/ast.hpp | 2 | ||||
-rwxr-xr-x | src/yuescript/yue_ast.h | 14 | ||||
-rwxr-xr-x | src/yuescript/yue_compiler.cpp | 87 | ||||
-rwxr-xr-x | src/yuescript/yue_parser.cpp | 12 | ||||
-rwxr-xr-x | src/yuescript/yue_parser.h | 2 |
7 files changed, 165 insertions, 9 deletions
diff --git a/spec/inputs/try-catch.yue b/spec/inputs/try-catch.yue new file mode 100644 index 0000000..ad8b1f0 --- /dev/null +++ b/spec/inputs/try-catch.yue | |||
@@ -0,0 +1,30 @@ | |||
1 | try | ||
2 | func 1, 2, 3 | ||
3 | catch err | ||
4 | print err | ||
5 | |||
6 | success, result = try | ||
7 | func 1, 2, 3 | ||
8 | catch err | ||
9 | print err | ||
10 | |||
11 | try func 1, 2, 3 | ||
12 | catch err | ||
13 | print err | ||
14 | |||
15 | success, result = try func 1, 2, 3 | ||
16 | |||
17 | try | ||
18 | print "trying" | ||
19 | func 1, 2, 3 | ||
20 | |||
21 | try tb.func | ||
22 | try tb.func! | ||
23 | try tb.func() | ||
24 | try (tb.func!) | ||
25 | |||
26 | try tb.func 1 | ||
27 | try tb.func(1) | ||
28 | |||
29 | nil | ||
30 | |||
diff --git a/spec/outputs/try-catch.lua b/spec/outputs/try-catch.lua new file mode 100644 index 0000000..25efda4 --- /dev/null +++ b/spec/outputs/try-catch.lua | |||
@@ -0,0 +1,27 @@ | |||
1 | xpcall(function() | ||
2 | return func(1, 2, 3) | ||
3 | end, function(err) | ||
4 | return print(err) | ||
5 | end) | ||
6 | local success, result = xpcall(function() | ||
7 | return func(1, 2, 3) | ||
8 | end, function(err) | ||
9 | return print(err) | ||
10 | end) | ||
11 | xpcall(func, function(err) | ||
12 | return print(err) | ||
13 | end, 1, 2, 3) | ||
14 | success, result = pcall(func, 1, 2, 3) | ||
15 | pcall(function() | ||
16 | print("trying") | ||
17 | return func(1, 2, 3) | ||
18 | end) | ||
19 | pcall(tb.func) | ||
20 | pcall(tb.func) | ||
21 | pcall(tb.func) | ||
22 | pcall((tb.func())) | ||
23 | pcall(tb.func, 1) | ||
24 | xpcall(tb.func, function(err) | ||
25 | return print(err) | ||
26 | end, 1) | ||
27 | return nil | ||
diff --git a/src/yuescript/ast.hpp b/src/yuescript/ast.hpp index 0636a74..6f89b52 100644 --- a/src/yuescript/ast.hpp +++ b/src/yuescript/ast.hpp | |||
@@ -364,7 +364,7 @@ private: | |||
364 | 364 | ||
365 | class _ast_list : public ast_member { | 365 | class _ast_list : public ast_member { |
366 | public: | 366 | public: |
367 | ~_ast_list() { | 367 | ~_ast_list() { |
368 | clear(); | 368 | clear(); |
369 | } | 369 | } |
370 | 370 | ||
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 79e35a5..d2a6557 100755 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h | |||
@@ -316,6 +316,18 @@ AST_NODE(Do) | |||
316 | AST_MEMBER(Do, &body) | 316 | AST_MEMBER(Do, &body) |
317 | AST_END(Do) | 317 | AST_END(Do) |
318 | 318 | ||
319 | AST_NODE(catch_block) | ||
320 | ast_ptr<true, Variable_t> err; | ||
321 | ast_ptr<true, Block_t> body; | ||
322 | AST_MEMBER(catch_block, &err, &body) | ||
323 | AST_END(catch_block) | ||
324 | |||
325 | AST_NODE(Try) | ||
326 | ast_sel<true, Block_t, Exp_t> func; | ||
327 | ast_ptr<false, catch_block_t> catchBlock; | ||
328 | AST_MEMBER(Try, &func, &catchBlock) | ||
329 | AST_END(Try) | ||
330 | |||
319 | class CompInner_t; | 331 | class CompInner_t; |
320 | class Statement_t; | 332 | class Statement_t; |
321 | 333 | ||
@@ -474,7 +486,7 @@ class FunLit_t; | |||
474 | AST_NODE(SimpleValue) | 486 | AST_NODE(SimpleValue) |
475 | ast_sel<true, const_value_t, | 487 | ast_sel<true, const_value_t, |
476 | If_t, Switch_t, With_t, ClassDecl_t, | 488 | If_t, Switch_t, With_t, ClassDecl_t, |
477 | ForEach_t, For_t, While_t, Do_t, | 489 | ForEach_t, For_t, While_t, Do_t, Try_t, |
478 | unary_value_t, | 490 | unary_value_t, |
479 | TblComprehension_t, TableLit_t, Comprehension_t, | 491 | TblComprehension_t, TableLit_t, Comprehension_t, |
480 | FunLit_t, Num_t> value; | 492 | FunLit_t, Num_t> value; |
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index fbb3fb5..2b9ebc9 100755 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
@@ -60,7 +60,7 @@ using namespace parserlib; | |||
60 | 60 | ||
61 | typedef std::list<std::string> str_list; | 61 | typedef std::list<std::string> str_list; |
62 | 62 | ||
63 | const std::string_view version = "0.9.11"sv; | 63 | const std::string_view version = "0.10.0"sv; |
64 | const std::string_view extension = "yue"sv; | 64 | const std::string_view extension = "yue"sv; |
65 | 65 | ||
66 | class YueCompilerImpl { | 66 | class YueCompilerImpl { |
@@ -576,8 +576,8 @@ private: | |||
576 | return exp; | 576 | return exp; |
577 | } | 577 | } |
578 | 578 | ||
579 | SimpleValue_t* simpleSingleValueFrom(ast_node* expList) const { | 579 | SimpleValue_t* simpleSingleValueFrom(ast_node* node) const { |
580 | auto value = singleValueFrom(expList); | 580 | auto value = singleValueFrom(node); |
581 | if (value && value->item.is<SimpleValue_t>()) { | 581 | if (value && value->item.is<SimpleValue_t>()) { |
582 | return static_cast<SimpleValue_t*>(value->item.get()); | 582 | return static_cast<SimpleValue_t*>(value->item.get()); |
583 | } | 583 | } |
@@ -1042,6 +1042,7 @@ private: | |||
1042 | case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break; | 1042 | case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break; |
1043 | case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break; | 1043 | case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break; |
1044 | case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break; | 1044 | case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break; |
1045 | case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break; | ||
1045 | case id<Comprehension_t>(): transformCompCommon(static_cast<Comprehension_t*>(value), out); break; | 1046 | case id<Comprehension_t>(): transformCompCommon(static_cast<Comprehension_t*>(value), out); break; |
1046 | default: specialSingleValue = false; break; | 1047 | default: specialSingleValue = false; break; |
1047 | } | 1048 | } |
@@ -2660,6 +2661,7 @@ private: | |||
2660 | case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break; | 2661 | case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break; |
2661 | case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break; | 2662 | case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break; |
2662 | case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break; | 2663 | case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break; |
2664 | case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Closure); break; | ||
2663 | case id<unary_value_t>(): transform_unary_value(static_cast<unary_value_t*>(value), out); break; | 2665 | case id<unary_value_t>(): transform_unary_value(static_cast<unary_value_t*>(value), out); break; |
2664 | case id<TblComprehension_t>(): transformTblComprehension(static_cast<TblComprehension_t*>(value), out, ExpUsage::Closure); break; | 2666 | case id<TblComprehension_t>(): transformTblComprehension(static_cast<TblComprehension_t*>(value), out, ExpUsage::Closure); break; |
2665 | case id<TableLit_t>(): transformTableLit(static_cast<TableLit_t*>(value), out); break; | 2667 | case id<TableLit_t>(): transformTableLit(static_cast<TableLit_t*>(value), out); break; |
@@ -6087,6 +6089,85 @@ private: | |||
6087 | out.push_back(join(temp)); | 6089 | out.push_back(join(temp)); |
6088 | } | 6090 | } |
6089 | 6091 | ||
6092 | void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage) { | ||
6093 | auto x = tryNode; | ||
6094 | ast_ptr<true, Exp_t> errHandler; | ||
6095 | if (tryNode->catchBlock) { | ||
6096 | auto errHandleStr = "("s + _parser.toString(tryNode->catchBlock->err) + ")->\n"s + _parser.toString(tryNode->catchBlock->body); | ||
6097 | errHandler.set(toAst<Exp_t>(errHandleStr, x)); | ||
6098 | } | ||
6099 | if (auto tryBlock = tryNode->func.as<Block_t>()) { | ||
6100 | auto tryExp = toAst<Exp_t>("->\n"s + _parser.toString(tryBlock), x); | ||
6101 | if (errHandler) { | ||
6102 | auto xpcall = toAst<ChainValue_t>("xpcall()", x); | ||
6103 | auto invoke = ast_to<Invoke_t>(xpcall->items.back()); | ||
6104 | invoke->args.push_back(tryExp); | ||
6105 | invoke->args.push_back(errHandler); | ||
6106 | transformChainValue(xpcall, out, ExpUsage::Closure); | ||
6107 | } else { | ||
6108 | auto pcall = toAst<ChainValue_t>("pcall()", x); | ||
6109 | auto invoke = ast_to<Invoke_t>(pcall->items.back()); | ||
6110 | invoke->args.push_back(tryExp); | ||
6111 | transformChainValue(pcall, out, ExpUsage::Closure); | ||
6112 | } | ||
6113 | if (usage == ExpUsage::Common) { | ||
6114 | out.back().append(nlr(x)); | ||
6115 | } | ||
6116 | return; | ||
6117 | } else if (auto value = singleValueFrom(tryNode->func)) { | ||
6118 | BLOCK_START | ||
6119 | auto chainValue = value->item.as<ChainValue_t>(); | ||
6120 | BREAK_IF(!chainValue); | ||
6121 | BREAK_IF(!isChainValueCall(chainValue)); | ||
6122 | ast_ptr<true, ast_node> last = chainValue->items.back(); | ||
6123 | chainValue->items.pop_back(); | ||
6124 | _ast_list* args = nullptr; | ||
6125 | if (auto invoke = ast_cast<InvokeArgs_t>(last)) { | ||
6126 | args = &invoke->args; | ||
6127 | } else { | ||
6128 | args = &(ast_to<Invoke_t>(last)->args); | ||
6129 | } | ||
6130 | if (errHandler) { | ||
6131 | auto xpcall = toAst<ChainValue_t>("xpcall()", x); | ||
6132 | auto invoke = ast_to<Invoke_t>(xpcall->items.back()); | ||
6133 | invoke->args.push_back(tryNode->func); | ||
6134 | invoke->args.push_back(errHandler); | ||
6135 | for (auto arg : args->objects()) { | ||
6136 | invoke->args.push_back(arg); | ||
6137 | } | ||
6138 | transformChainValue(xpcall, out, ExpUsage::Closure); | ||
6139 | } else { | ||
6140 | auto pcall = toAst<ChainValue_t>("pcall()", x); | ||
6141 | auto invoke = ast_to<Invoke_t>(pcall->items.back()); | ||
6142 | invoke->args.push_back(tryNode->func); | ||
6143 | for (auto arg : args->objects()) { | ||
6144 | invoke->args.push_back(arg); | ||
6145 | } | ||
6146 | transformChainValue(pcall, out, ExpUsage::Closure); | ||
6147 | } | ||
6148 | if (usage == ExpUsage::Common) { | ||
6149 | out.back().append(nlr(x)); | ||
6150 | } | ||
6151 | return; | ||
6152 | BLOCK_END | ||
6153 | } | ||
6154 | if (errHandler) { | ||
6155 | auto xpcall = toAst<ChainValue_t>("xpcall()", x); | ||
6156 | auto invoke = ast_to<Invoke_t>(xpcall->items.back()); | ||
6157 | invoke->args.push_back(tryNode->func); | ||
6158 | invoke->args.push_back(errHandler); | ||
6159 | transformChainValue(xpcall, out, ExpUsage::Closure); | ||
6160 | } else { | ||
6161 | auto pcall = toAst<ChainValue_t>("pcall()", x); | ||
6162 | auto invoke = ast_to<Invoke_t>(pcall->items.back()); | ||
6163 | invoke->args.push_back(tryNode->func); | ||
6164 | transformChainValue(pcall, out, ExpUsage::Closure); | ||
6165 | } | ||
6166 | if (usage == ExpUsage::Common) { | ||
6167 | out.back().append(nlr(x)); | ||
6168 | } | ||
6169 | } | ||
6170 | |||
6090 | void transformImportFrom(ImportFrom_t* import, str_list& out) { | 6171 | void transformImportFrom(ImportFrom_t* import, str_list& out) { |
6091 | str_list temp; | 6172 | str_list temp; |
6092 | auto x = import; | 6173 | auto x = import; |
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 3d12190..8325366 100755 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp | |||
@@ -29,7 +29,8 @@ std::unordered_set<std::string> Keywords = { | |||
29 | "until", "while", // Lua keywords | 29 | "until", "while", // Lua keywords |
30 | "as", "class", "continue", "export", "extends", | 30 | "as", "class", "continue", "export", "extends", |
31 | "from", "global", "import", "is", "macro", | 31 | "from", "global", "import", "is", "macro", |
32 | "switch", "unless", "using", "when", "with" // Yue keywords | 32 | "switch", "try", "unless", "using", "when", |
33 | "with" // Yue keywords | ||
33 | }; | 34 | }; |
34 | 35 | ||
35 | YueParser::YueParser() { | 36 | YueParser::YueParser() { |
@@ -229,8 +230,8 @@ YueParser::YueParser() { | |||
229 | SwitchBlock = *EmptyLine >> | 230 | SwitchBlock = *EmptyLine >> |
230 | Advance >> Seperator >> | 231 | Advance >> Seperator >> |
231 | SwitchCase >> | 232 | SwitchCase >> |
232 | *(+SpaceBreak >> SwitchCase) >> | 233 | *(Break >> *EmptyLine >> CheckIndent >> SwitchCase) >> |
233 | -(+SpaceBreak >> SwitchElse) >> | 234 | -(Break >> *EmptyLine >> CheckIndent >> SwitchElse) >> |
234 | PopIndent; | 235 | PopIndent; |
235 | 236 | ||
236 | Switch = Space >> key("switch") >> disable_do(Exp) >> -(Space >> key("do")) | 237 | Switch = Space >> key("switch") >> disable_do(Exp) >> -(Space >> key("do")) |
@@ -299,6 +300,9 @@ YueParser::YueParser() { | |||
299 | return true; | 300 | return true; |
300 | }); | 301 | }); |
301 | 302 | ||
303 | catch_block = Break >> *EmptyLine >> CheckIndent >> Space >> key("catch") >> Space >> Variable >> InBlock; | ||
304 | Try = Space >> key("try") >> (InBlock | Exp) >> -catch_block; | ||
305 | |||
302 | Comprehension = sym('[') >> Exp >> Space >> CompInner >> sym(']'); | 306 | Comprehension = sym('[') >> Exp >> Space >> CompInner >> sym(']'); |
303 | comp_value = sym(',') >> Exp; | 307 | comp_value = sym(',') >> Exp; |
304 | TblComprehension = sym('{') >> Exp >> -comp_value >> Space >> CompInner >> sym('}'); | 308 | TblComprehension = sym('{') >> Exp >> -comp_value >> Space >> CompInner >> sym('}'); |
@@ -609,7 +613,7 @@ YueParser::YueParser() { | |||
609 | const_value = (expr("nil") | expr("true") | expr("false")) >> not_(AlphaNum); | 613 | const_value = (expr("nil") | expr("true") | expr("false")) >> not_(AlphaNum); |
610 | 614 | ||
611 | SimpleValue = Space >> (const_value | | 615 | SimpleValue = Space >> (const_value | |
612 | If | Switch | With | ClassDecl | ForEach | For | While | Do | | 616 | If | Switch | Try | With | ClassDecl | ForEach | For | While | Do | |
613 | unary_value | TblComprehension | TableLit | Comprehension | | 617 | unary_value | TblComprehension | TableLit | Comprehension | |
614 | FunLit | Num); | 618 | FunLit | Num); |
615 | 619 | ||
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 7dea126..bd86f50 100755 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h | |||
@@ -238,6 +238,8 @@ private: | |||
238 | AST_RULE(For) | 238 | AST_RULE(For) |
239 | AST_RULE(ForEach) | 239 | AST_RULE(ForEach) |
240 | AST_RULE(Do) | 240 | AST_RULE(Do) |
241 | AST_RULE(catch_block) | ||
242 | AST_RULE(Try) | ||
241 | AST_RULE(Comprehension) | 243 | AST_RULE(Comprehension) |
242 | AST_RULE(comp_value) | 244 | AST_RULE(comp_value) |
243 | AST_RULE(TblComprehension) | 245 | AST_RULE(TblComprehension) |