diff --git a/doc/17-language-reference.md b/doc/17-language-reference.md
index 7aa58bbe8..adc20520f 100644
--- a/doc/17-language-reference.md
+++ b/doc/17-language-reference.md
@@ -851,7 +851,7 @@ Example:
var s = String(3) /* Sets s to "3". */
-## Exceptions
+## Throwing Exceptions
Built-in commands may throw exceptions to signal errors such as invalid arguments. User scripts can throw exceptions
using the `throw` keyword.
@@ -860,7 +860,20 @@ Example:
throw "An error occurred."
-There is currently no way for scripts to catch exceptions.
+## Handling Exceptions
+
+Exceptions can be handled using the `try` and `except` keywords. When an exception occurs while executing code in the
+`try` clause no further statements in the `try` clause are evaluated and the `except` clause is executed instead.
+
+Example:
+
+ try {
+ throw "Test"
+
+ log("This statement won't get executed.")
+ } except {
+ log("An error occurred in the try clause.")
+ }
## Breakpoints
@@ -920,7 +933,7 @@ These keywords are reserved and must not be used as constants or custom attribut
template
include
include_recursive
- ignore_on_error
+ include_zones
library
null
true
@@ -928,7 +941,13 @@ These keywords are reserved and must not be used as constants or custom attribut
const
var
this
+ globals
+ locals
use
+ default
+ ignore_on_error
+ current_filename
+ current_line
apply
to
where
@@ -937,12 +956,16 @@ These keywords are reserved and must not be used as constants or custom attribut
ignore
function
return
+ break
+ continue
for
if
else
+ while
+ throw
+ try
+ except
in
- current_filename
- current_line
You can escape reserved keywords using the `@` character. The following example
tries to set `vars.include` which references a reserved keyword and generates
diff --git a/lib/base/configwriter.cpp b/lib/base/configwriter.cpp
index 75d0752b5..05ddb30aa 100644
--- a/lib/base/configwriter.cpp
+++ b/lib/base/configwriter.cpp
@@ -262,6 +262,8 @@ const std::vector& ConfigWriter::GetKeywords(void)
keywords.push_back("else");
keywords.push_back("while");
keywords.push_back("throw");
+ keywords.push_back("try");
+ keywords.push_back("except");
}
return keywords;
diff --git a/lib/config/config_lexer.ll b/lib/config/config_lexer.ll
index 920e13d2e..d636b811f 100644
--- a/lib/config/config_lexer.ll
+++ b/lib/config/config_lexer.ll
@@ -197,6 +197,8 @@ if return T_IF;
else return T_ELSE;
while return T_WHILE;
throw return T_THROW;
+try return T_TRY;
+except return T_EXCEPT;
ignore_on_error return T_IGNORE_ON_ERROR;
current_filename return T_CURRENT_FILENAME;
current_line return T_CURRENT_LINE;
diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy
index a02bf2915..36f972410 100644
--- a/lib/config/config_parser.yy
+++ b/lib/config/config_parser.yy
@@ -172,6 +172,8 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig
%token T_ELSE "else (T_ELSE)"
%token T_WHILE "while (T_WHILE)"
%token T_THROW "throw (T_THROW)"
+%token T_TRY "try (T_TRY)"
+%token T_EXCEPT "except (T_EXCEPT)"
%token T_FOLLOWS "=> (T_FOLLOWS)"
%token T_NULLARY_LAMBDA_BEGIN "{{ (T_NULLARY_LAMBDA_BEGIN)"
%token T_NULLARY_LAMBDA_END "}} (T_NULLARY_LAMBDA_END)"
@@ -666,6 +668,10 @@ lterm: T_LIBRARY rterm
{
$$ = new ThrowExpression($2, false, @$);
}
+ | T_TRY rterm_scope T_EXCEPT rterm_scope
+ {
+ $$ = new TryExceptExpression($2, $4, @$);
+ }
| rterm_side_effect
;
diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp
index b0e1b6cad..3f95435a0 100644
--- a/lib/config/expression.cpp
+++ b/lib/config/expression.cpp
@@ -941,3 +941,16 @@ ExpressionResult UsingExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhin
return Empty;
}
+ExpressionResult TryExceptExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
+{
+ try {
+ ExpressionResult tryResult = m_TryBody->Evaluate(frame, dhint);
+ CHECK_RESULT(tryResult);
+ } catch (const std::exception& ex) {
+ ExpressionResult exceptResult = m_ExceptBody->Evaluate(frame, dhint);
+ CHECK_RESULT(exceptResult);
+ }
+
+ return Empty;
+}
+
diff --git a/lib/config/expression.hpp b/lib/config/expression.hpp
index a4c46dc06..bc90ef481 100644
--- a/lib/config/expression.hpp
+++ b/lib/config/expression.hpp
@@ -1027,6 +1027,27 @@ private:
Expression *m_Name;
};
+class I2_CONFIG_API TryExceptExpression : public DebuggableExpression
+{
+public:
+ TryExceptExpression(Expression *tryBody, Expression *exceptBody, const DebugInfo& debugInfo = DebugInfo())
+ : DebuggableExpression(debugInfo), m_TryBody(tryBody), m_ExceptBody(exceptBody)
+ { }
+
+ ~TryExceptExpression(void)
+ {
+ delete m_TryBody;
+ delete m_ExceptBody;
+ }
+
+protected:
+ virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override;
+
+private:
+ Expression *m_TryBody;
+ Expression *m_ExceptBody;
+};
+
}
#endif /* EXPRESSION_H */