diff --git a/doc/17-language-reference.md b/doc/17-language-reference.md
index 53bea28a3..efbe48a86 100644
--- a/doc/17-language-reference.md
+++ b/doc/17-language-reference.md
@@ -1049,6 +1049,14 @@ function MakeHelloFunction(name) {
}
```
+The `use` keyword also supports `this`, i.e.:
+
+```
+(function() use (this = [ "foo", "bar" ]) {
+ log(this)
+})()
+```
+
## Conditional Statements
### Conditional Statements: if/else
diff --git a/lib/base/function.cpp b/lib/base/function.cpp
index f9a261dc0..9bd254d88 100644
--- a/lib/base/function.cpp
+++ b/lib/base/function.cpp
@@ -10,8 +10,9 @@ using namespace icinga;
REGISTER_TYPE_WITH_PROTOTYPE(Function, Function::GetPrototype());
Function::Function(const String& name, Callback function, const std::vector& args,
+ bool hasClosedThis, Value closedThis,
bool side_effect_free, bool deprecated)
- : m_Callback(std::move(function))
+ : m_Callback(std::move(function)), m_HasClosedThis(hasClosedThis), m_ClosedThis(std::move(closedThis))
{
SetName(name, true);
SetSideEffectFree(side_effect_free, true);
@@ -21,6 +22,10 @@ Function::Function(const String& name, Callback function, const std::vector& arguments)
{
+ if (m_HasClosedThis) {
+ return InvokeThis(m_ClosedThis, arguments);
+ }
+
ScriptFrame frame(false);
return m_Callback(arguments);
}
diff --git a/lib/base/function.hpp b/lib/base/function.hpp
index d52a230a1..39e847519 100644
--- a/lib/base/function.hpp
+++ b/lib/base/function.hpp
@@ -27,8 +27,9 @@ public:
template
Function(const String& name, F function, const std::vector& args = std::vector(),
+ bool hasClosedThis = false, Value closedThis = Value(),
bool side_effect_free = false, bool deprecated = false)
- : Function(name, WrapFunction(function), args, side_effect_free, deprecated)
+ : Function(name, WrapFunction(function), args, hasClosedThis, std::move(closedThis), side_effect_free, deprecated)
{ }
Value Invoke(const std::vector& arguments = std::vector());
@@ -50,8 +51,11 @@ public:
private:
Callback m_Callback;
+ bool m_HasClosedThis;
+ Value m_ClosedThis;
Function(const String& name, Callback function, const std::vector& args,
+ bool hasClosedThis, Value closedThis,
bool side_effect_free, bool deprecated);
};
diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy
index 939681e68..bf9494f3c 100644
--- a/lib/config/config_parser.yy
+++ b/lib/config/config_parser.yy
@@ -1103,6 +1103,14 @@ use_specifier_item: identifier
$$ = new std::pair >(std::move(*$1), std::unique_ptr($3));
delete $1;
}
+ | T_THIS
+ {
+ $$ = new std::pair >("this", std::unique_ptr(new GetScopeExpression(ScopeThis)));
+ }
+ | T_THIS T_SET rterm
+ {
+ $$ = new std::pair >("this", std::unique_ptr($3));
+ }
;
apply_for_specifier: /* empty */
diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp
index 09b860cde..d13fd4e19 100644
--- a/lib/config/expression.cpp
+++ b/lib/config/expression.cpp
@@ -904,7 +904,7 @@ ExpressionResult ImportDefaultTemplatesExpression::DoEvaluate(ScriptFrame& frame
ExpressionResult FunctionExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{
- return VMOps::NewFunction(frame, m_Name, m_Args, m_ClosedVars, m_Expression);
+ return VMOps::NewFunction(frame, m_Name, m_Args, m_ClosedVars, m_ClosedThis, m_Expression);
}
ExpressionResult ApplyExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
diff --git a/lib/config/expression.hpp b/lib/config/expression.hpp
index 644548d28..07f075729 100644
--- a/lib/config/expression.hpp
+++ b/lib/config/expression.hpp
@@ -814,7 +814,14 @@ public:
FunctionExpression(String name, std::vector args,
std::map >&& closedVars, std::unique_ptr expression, const DebugInfo& debugInfo = DebugInfo())
: DebuggableExpression(debugInfo), m_Name(std::move(name)), m_Args(std::move(args)), m_ClosedVars(std::move(closedVars)), m_Expression(expression.release())
- { }
+ {
+ auto closedThis (m_ClosedVars.find("this"));
+
+ if (closedThis != m_ClosedVars.end()) {
+ m_ClosedThis = std::move(closedThis->second);
+ m_ClosedVars.erase(closedThis);
+ }
+ }
protected:
ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override;
@@ -823,6 +830,7 @@ private:
String m_Name;
std::vector m_Args;
std::map > m_ClosedVars;
+ std::unique_ptr m_ClosedThis;
Expression::Ptr m_Expression;
};
diff --git a/lib/config/vmops.hpp b/lib/config/vmops.hpp
index ea3098359..2cc33f383 100644
--- a/lib/config/vmops.hpp
+++ b/lib/config/vmops.hpp
@@ -91,9 +91,15 @@ public:
}
static inline Value NewFunction(ScriptFrame& frame, const String& name, const std::vector& argNames,
- const std::map >& closedVars, const Expression::Ptr& expression)
+ const std::map >& closedVars,
+ const std::unique_ptr& closedThis, const Expression::Ptr& expression)
{
auto evaluatedClosedVars = EvaluateClosedVars(frame, closedVars);
+ Value evaluatedClosedThis;
+
+ if (closedThis) {
+ evaluatedClosedThis = closedThis->Evaluate(frame);
+ }
auto wrapper = [argNames, evaluatedClosedVars, expression](const std::vector& arguments) -> Value {
if (arguments.size() < argNames.size())
@@ -112,7 +118,7 @@ public:
return expression->Evaluate(*frame);
};
- return new Function(name, wrapper, argNames);
+ return new Function(name, wrapper, argNames, (bool)closedThis, std::move(evaluatedClosedThis));
}
static inline Value NewApply(ScriptFrame& frame, const String& type, const String& target, const String& name, const Expression::Ptr& filter,