DSL: allow function()use(this){} and function()use(this=x){}

This commit is contained in:
Alexander A. Klimov 2020-01-07 11:42:11 +01:00
parent a65f2d6b41
commit 5683a03f55
7 changed files with 45 additions and 6 deletions

View File

@ -1049,6 +1049,14 @@ function MakeHelloFunction(name) {
}
```
The `use` keyword also supports `this`, i.e.:
```
(function() use (this = [ "foo", "bar" ]) {
log(this)
})()
```
## Conditional Statements <a id="conditional-statements"></a>
### Conditional Statements: if/else <a id="conditional-statements-if-else"></a>

View File

@ -10,8 +10,9 @@ using namespace icinga;
REGISTER_TYPE_WITH_PROTOTYPE(Function, Function::GetPrototype());
Function::Function(const String& name, Callback function, const std::vector<String>& 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<Stri
Value Function::Invoke(const std::vector<Value>& arguments)
{
if (m_HasClosedThis) {
return InvokeThis(m_ClosedThis, arguments);
}
ScriptFrame frame(false);
return m_Callback(arguments);
}

View File

@ -27,8 +27,9 @@ public:
template<typename F>
Function(const String& name, F function, const std::vector<String>& args = std::vector<String>(),
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<Value>& arguments = std::vector<Value>());
@ -50,8 +51,11 @@ public:
private:
Callback m_Callback;
bool m_HasClosedThis;
Value m_ClosedThis;
Function(const String& name, Callback function, const std::vector<String>& args,
bool hasClosedThis, Value closedThis,
bool side_effect_free, bool deprecated);
};

View File

@ -1103,6 +1103,14 @@ use_specifier_item: identifier
$$ = new std::pair<String, std::unique_ptr<Expression> >(std::move(*$1), std::unique_ptr<Expression>($3));
delete $1;
}
| T_THIS
{
$$ = new std::pair<String, std::unique_ptr<Expression> >("this", std::unique_ptr<Expression>(new GetScopeExpression(ScopeThis)));
}
| T_THIS T_SET rterm
{
$$ = new std::pair<String, std::unique_ptr<Expression> >("this", std::unique_ptr<Expression>($3));
}
;
apply_for_specifier: /* empty */

View File

@ -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

View File

@ -814,7 +814,14 @@ public:
FunctionExpression(String name, std::vector<String> args,
std::map<String, std::unique_ptr<Expression> >&& closedVars, std::unique_ptr<Expression> 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<String> m_Args;
std::map<String, std::unique_ptr<Expression> > m_ClosedVars;
std::unique_ptr<Expression> m_ClosedThis;
Expression::Ptr m_Expression;
};

View File

@ -91,9 +91,15 @@ public:
}
static inline Value NewFunction(ScriptFrame& frame, const String& name, const std::vector<String>& argNames,
const std::map<String, std::unique_ptr<Expression> >& closedVars, const Expression::Ptr& expression)
const std::map<String, std::unique_ptr<Expression> >& closedVars,
const std::unique_ptr<Expression>& 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<Value>& 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,