From 7167828a9d873156ad208d161cd1a2dc8ab78523 Mon Sep 17 00:00:00 2001
From: Li Jin <dragon-fly@qq.com>
Date: Mon, 21 Feb 2022 14:07:07 +0800
Subject: fixing issue #80.

---
 src/yuescript/ast.hpp          |  2 +-
 src/yuescript/yue_ast.h        | 14 ++++++-
 src/yuescript/yue_compiler.cpp | 87 ++++++++++++++++++++++++++++++++++++++++--
 src/yuescript/yue_parser.cpp   | 12 ++++--
 src/yuescript/yue_parser.h     |  2 +
 5 files changed, 108 insertions(+), 9 deletions(-)

(limited to 'src')

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:
 
 class _ast_list : public ast_member {
 public:
-   ~_ast_list() {
+	~_ast_list() {
 		clear();
 	}
 
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)
 	AST_MEMBER(Do, &body)
 AST_END(Do)
 
+AST_NODE(catch_block)
+	ast_ptr<true, Variable_t> err;
+	ast_ptr<true, Block_t> body;
+	AST_MEMBER(catch_block, &err, &body)
+AST_END(catch_block)
+
+AST_NODE(Try)
+	ast_sel<true, Block_t, Exp_t> func;
+	ast_ptr<false, catch_block_t> catchBlock;
+	AST_MEMBER(Try, &func, &catchBlock)
+AST_END(Try)
+
 class CompInner_t;
 class Statement_t;
 
@@ -474,7 +486,7 @@ class FunLit_t;
 AST_NODE(SimpleValue)
 	ast_sel<true, const_value_t,
 	If_t, Switch_t, With_t, ClassDecl_t,
-	ForEach_t, For_t, While_t, Do_t,
+	ForEach_t, For_t, While_t, Do_t, Try_t,
 	unary_value_t,
 	TblComprehension_t, TableLit_t, Comprehension_t,
 	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;
 
 typedef std::list<std::string> str_list;
 
-const std::string_view version = "0.9.11"sv;
+const std::string_view version = "0.10.0"sv;
 const std::string_view extension = "yue"sv;
 
 class YueCompilerImpl {
@@ -576,8 +576,8 @@ private:
 		return exp;
 	}
 
-	SimpleValue_t* simpleSingleValueFrom(ast_node* expList) const {
-		auto value = singleValueFrom(expList);
+	SimpleValue_t* simpleSingleValueFrom(ast_node* node) const {
+		auto value = singleValueFrom(node);
 		if (value && value->item.is<SimpleValue_t>()) {
 			return static_cast<SimpleValue_t*>(value->item.get());
 		}
@@ -1042,6 +1042,7 @@ private:
 								case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break;
 								case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break;
 								case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break;
+								case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break;
 								case id<Comprehension_t>(): transformCompCommon(static_cast<Comprehension_t*>(value), out); break;
 								default: specialSingleValue = false; break;
 							}
@@ -2660,6 +2661,7 @@ private:
 			case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break;
 			case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break;
 			case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break;
+			case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Closure); break;
 			case id<unary_value_t>(): transform_unary_value(static_cast<unary_value_t*>(value), out); break;
 			case id<TblComprehension_t>(): transformTblComprehension(static_cast<TblComprehension_t*>(value), out, ExpUsage::Closure); break;
 			case id<TableLit_t>(): transformTableLit(static_cast<TableLit_t*>(value), out); break;
@@ -6087,6 +6089,85 @@ private:
 		out.push_back(join(temp));
 	}
 
+	void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage) {
+		auto x = tryNode;
+		ast_ptr<true, Exp_t> errHandler;
+		if (tryNode->catchBlock) {
+			auto errHandleStr = "("s + _parser.toString(tryNode->catchBlock->err) + ")->\n"s + _parser.toString(tryNode->catchBlock->body);
+			errHandler.set(toAst<Exp_t>(errHandleStr, x));
+		}
+		if (auto tryBlock = tryNode->func.as<Block_t>()) {
+			auto tryExp = toAst<Exp_t>("->\n"s + _parser.toString(tryBlock), x);
+			if (errHandler) {
+				auto xpcall = toAst<ChainValue_t>("xpcall()", x);
+				auto invoke = ast_to<Invoke_t>(xpcall->items.back());
+				invoke->args.push_back(tryExp);
+				invoke->args.push_back(errHandler);
+				transformChainValue(xpcall, out, ExpUsage::Closure);
+			} else {
+				auto pcall = toAst<ChainValue_t>("pcall()", x);
+				auto invoke = ast_to<Invoke_t>(pcall->items.back());
+				invoke->args.push_back(tryExp);
+				transformChainValue(pcall, out, ExpUsage::Closure);
+			}
+			if (usage == ExpUsage::Common) {
+				out.back().append(nlr(x));
+			}
+			return;
+		} else if (auto value = singleValueFrom(tryNode->func)) {
+			BLOCK_START
+			auto chainValue = value->item.as<ChainValue_t>();
+			BREAK_IF(!chainValue);
+			BREAK_IF(!isChainValueCall(chainValue));
+			ast_ptr<true, ast_node> last = chainValue->items.back();
+			chainValue->items.pop_back();
+			_ast_list* args = nullptr;
+			if (auto invoke = ast_cast<InvokeArgs_t>(last)) {
+				args = &invoke->args;
+			} else {
+				args = &(ast_to<Invoke_t>(last)->args);
+			}
+			if (errHandler) {
+				auto xpcall = toAst<ChainValue_t>("xpcall()", x);
+				auto invoke = ast_to<Invoke_t>(xpcall->items.back());
+				invoke->args.push_back(tryNode->func);
+				invoke->args.push_back(errHandler);
+				for (auto arg : args->objects()) {
+					invoke->args.push_back(arg);
+				}
+				transformChainValue(xpcall, out, ExpUsage::Closure);
+			} else {
+				auto pcall = toAst<ChainValue_t>("pcall()", x);
+				auto invoke = ast_to<Invoke_t>(pcall->items.back());
+				invoke->args.push_back(tryNode->func);
+				for (auto arg : args->objects()) {
+					invoke->args.push_back(arg);
+				}
+				transformChainValue(pcall, out, ExpUsage::Closure);
+			}
+			if (usage == ExpUsage::Common) {
+				out.back().append(nlr(x));
+			}
+			return;
+			BLOCK_END
+		}
+		if (errHandler) {
+			auto xpcall = toAst<ChainValue_t>("xpcall()", x);
+			auto invoke = ast_to<Invoke_t>(xpcall->items.back());
+			invoke->args.push_back(tryNode->func);
+			invoke->args.push_back(errHandler);
+			transformChainValue(xpcall, out, ExpUsage::Closure);
+		} else {
+			auto pcall = toAst<ChainValue_t>("pcall()", x);
+			auto invoke = ast_to<Invoke_t>(pcall->items.back());
+			invoke->args.push_back(tryNode->func);
+			transformChainValue(pcall, out, ExpUsage::Closure);
+		}
+		if (usage == ExpUsage::Common) {
+			out.back().append(nlr(x));
+		}
+	}
+
 	void transformImportFrom(ImportFrom_t* import, str_list& out) {
 		str_list temp;
 		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 = {
 	"until", "while", // Lua keywords
 	"as", "class", "continue", "export", "extends",
 	"from", "global", "import", "is", "macro",
-	"switch", "unless", "using", "when", "with" // Yue keywords
+	"switch", "try", "unless", "using", "when",
+	"with" // Yue keywords
 };
 
 YueParser::YueParser() {
@@ -229,8 +230,8 @@ YueParser::YueParser() {
 	SwitchBlock = *EmptyLine >>
 		Advance >> Seperator >>
 		SwitchCase >>
-		*(+SpaceBreak >> SwitchCase) >>
-		-(+SpaceBreak >> SwitchElse) >>
+		*(Break >> *EmptyLine >> CheckIndent >> SwitchCase) >>
+		-(Break >> *EmptyLine >> CheckIndent >> SwitchElse) >>
 		PopIndent;
 
 	Switch = Space >> key("switch") >> disable_do(Exp) >> -(Space >> key("do"))
@@ -299,6 +300,9 @@ YueParser::YueParser() {
 		return true;
 	});
 
+	catch_block = Break >> *EmptyLine >> CheckIndent >> Space >> key("catch") >> Space >> Variable >> InBlock;
+	Try = Space >> key("try") >> (InBlock | Exp) >> -catch_block;
+
 	Comprehension = sym('[') >> Exp >> Space >> CompInner >> sym(']');
 	comp_value = sym(',') >> Exp;
 	TblComprehension = sym('{') >> Exp >> -comp_value >> Space >> CompInner >> sym('}');
@@ -609,7 +613,7 @@ YueParser::YueParser() {
 	const_value = (expr("nil") | expr("true") | expr("false")) >> not_(AlphaNum);
 
 	SimpleValue = Space >> (const_value |
-		If | Switch | With | ClassDecl | ForEach | For | While | Do |
+		If | Switch | Try | With | ClassDecl | ForEach | For | While | Do |
 		unary_value | TblComprehension | TableLit | Comprehension |
 		FunLit | Num);
 
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:
 	AST_RULE(For)
 	AST_RULE(ForEach)
 	AST_RULE(Do)
+	AST_RULE(catch_block)
+	AST_RULE(Try)
 	AST_RULE(Comprehension)
 	AST_RULE(comp_value)
 	AST_RULE(TblComprehension)
-- 
cgit v1.2.3-55-g6feb