Allow anonymous functions to be garbage-collected.

Fixes #5921
This commit is contained in:
Gunnar Beutner 2014-04-02 09:04:17 +02:00
parent ebf8ed3019
commit 0683fca535
4 changed files with 35 additions and 38 deletions

View File

@ -233,15 +233,21 @@ Value DynamicObject::InvokeMethod(const String& method,
if (!methods)
BOOST_THROW_EXCEPTION(std::invalid_argument("Method '" + method + "' does not exist."));
String funcName = methods->Get(method);
Value funcName = methods->Get(method);
if (funcName.IsEmpty())
BOOST_THROW_EXCEPTION(std::invalid_argument("Method '" + method + "' does not exist."));
ScriptFunction::Ptr func = ScriptFunctionRegistry::GetInstance()->GetItem(funcName);
ScriptFunction::Ptr func;
if (!func)
BOOST_THROW_EXCEPTION(std::invalid_argument("Function '" + funcName + "' does not exist."));
if (funcName.IsObjectType<ScriptFunction>()) {
func = funcName;
} else {
func = ScriptFunction::GetByName(funcName);
if (!func)
BOOST_THROW_EXCEPTION(std::invalid_argument("Function '" + String(funcName) + "' does not exist."));
}
return func->Invoke(arguments);
}

View File

@ -35,31 +35,27 @@ Value ScriptFunction::Invoke(const std::vector<Value>& arguments)
ScriptFunction::Ptr ScriptFunction::GetByName(const String& name)
{
return ScriptFunctionRegistry::GetInstance()->GetItem(name);
ScriptVariable::Ptr sv = ScriptVariable::GetByName(name);
if (!sv)
return ScriptFunction::Ptr();
return sv->GetData();
}
void ScriptFunction::Register(const String& name, const ScriptFunction::Callback& function)
void ScriptFunction::Register(const String& name, const ScriptFunction::Ptr& function)
{
ScriptVariable::Ptr sv = ScriptVariable::Set(name, name);
ScriptVariable::Ptr sv = ScriptVariable::Set(name, function);
sv->SetConstant(true);
ScriptFunction::Ptr func = make_shared<ScriptFunction>(function);
ScriptFunctionRegistry::GetInstance()->Register(name, func);
}
void ScriptFunction::Unregister(const String& name)
{
ScriptVariable::Unregister(name);
ScriptFunctionRegistry::GetInstance()->Unregister(name);
}
RegisterFunctionHelper::RegisterFunctionHelper(const String& name, const ScriptFunction::Callback& function)
{
ScriptFunction::Register(name, function);
}
ScriptFunctionRegistry *ScriptFunctionRegistry::GetInstance(void)
{
return Singleton<ScriptFunctionRegistry>::GetInstance();
ScriptFunction::Register(name, make_shared<ScriptFunction>(function));
}

View File

@ -48,24 +48,13 @@ public:
Value Invoke(const std::vector<Value>& arguments);
static ScriptFunction::Ptr GetByName(const String& name);
static void Register(const String& name, const ScriptFunction::Callback& function);
static void Register(const String& name, const ScriptFunction::Ptr& function);
static void Unregister(const String& name);
private:
Callback m_Callback;
};
/**
* A registry for script functions.
*
* @ingroup base
*/
class I2_BASE_API ScriptFunctionRegistry : public Registry<ScriptFunctionRegistry, ScriptFunction::Ptr>
{
public:
static ScriptFunctionRegistry *GetInstance(void);
};
/**
* Helper class for registering ScriptFunction implementation classes.
*

View File

@ -248,8 +248,14 @@ Value AExpression::OpLogicalOr(const AExpression *expr, const Dictionary::Ptr& l
Value AExpression::OpFunctionCall(const AExpression *expr, const Dictionary::Ptr& locals)
{
String funcName = expr->EvaluateOperand1(locals);
ScriptFunction::Ptr func = ScriptFunction::GetByName(funcName);
Value funcName = expr->EvaluateOperand1(locals);
ScriptFunction::Ptr func;
if (funcName.IsObjectType<ScriptFunction>())
func = funcName;
else
func = ScriptFunction::GetByName(funcName);
if (!func)
BOOST_THROW_EXCEPTION(ConfigError("Function '" + funcName + "' does not exist."));
@ -478,13 +484,13 @@ Value AExpression::OpFunction(const AExpression* expr, const Dictionary::Ptr& lo
AExpression::Ptr aexpr = left->Get(1);
String name = left->Get(0);
if (name.IsEmpty())
name = "__lambda" + Utility::NewUniqueID();
Array::Ptr funcargs = expr->m_Operand2;
ScriptFunction::Callback callback = boost::bind(&AExpression::FunctionWrapper, _1, funcargs, aexpr, locals);
ScriptFunction::Register(name, callback);
return name;
ScriptFunction::Ptr func = make_shared<ScriptFunction>(boost::bind(&AExpression::FunctionWrapper, _1, funcargs, aexpr, locals));
if (!name.IsEmpty())
ScriptFunction::Register(name, func);
return func;
}
Value AExpression::OpApply(const AExpression* expr, const Dictionary::Ptr& locals)
@ -538,4 +544,4 @@ Value AExpression::OpObject(const AExpression* expr, const Dictionary::Ptr& loca
item->Compile()->Register();
return Empty;
}
}