1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-31 03:00:05 +00:00

Added a method JavascriptEngine::callFunction(), and tweaked the way timeouts are specified.

This commit is contained in:
jules 2013-10-17 16:34:09 +01:00
parent a074bfeea2
commit fb4912ac1f
2 changed files with 83 additions and 40 deletions

View file

@ -68,6 +68,8 @@ struct JavascriptEngine::RootObject : public DynamicObject
setMethod ("parseInt", IntegerClass::parseInt);
}
Time timeout;
typedef const var::NativeFunctionArgs& Args;
typedef const char* TokenType;
@ -83,7 +85,14 @@ struct JavascriptEngine::RootObject : public DynamicObject
return ExpPtr (tb.parseExpression())->getResult (Scope (nullptr, this, this));
}
Time timeout;
var invoke (Identifier function, const var::NativeFunctionArgs& args)
{
if (const var* m = getProperties().getVarPointer (function))
if (FunctionObject* fo = dynamic_cast<FunctionObject*> (m->getObject()))
return fo->invoke (Scope (nullptr, this, this), args);
return var::undefined();
}
//==============================================================================
static bool areTypeEqual (const var& a, const var& b)
@ -646,7 +655,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
if (DotOperator* dot = dynamic_cast<DotOperator*> (object.get()))
{
var thisObject = dot->parent->getResult (s);
var thisObject (dot->parent->getResult (s));
return invokeFunction (s, s.findFunctionCall (location, thisObject, dot->child), thisObject);
}
@ -655,35 +664,21 @@ struct JavascriptEngine::RootObject : public DynamicObject
var invokeFunction (const Scope& s, const var& function, const var& thisObject) const
{
s.checkTimeOut (location);
Array<var> argVars;
for (int i = 0; i < arguments.size(); ++i)
argVars.add (arguments.getUnchecked(i)->getResult (s));
const var::NativeFunctionArgs args (thisObject, argVars.begin(), argVars.size());
if (var::NativeFunction nativeFunction = function.getNativeFunction())
{
Array<var> args;
for (int i = 0; i < arguments.size(); ++i)
args.add (arguments.getUnchecked(i)->getResult (s));
return nativeFunction (var::NativeFunctionArgs (thisObject, args.getRawDataPointer(), args.size()));
}
var result;
return nativeFunction (args);
if (FunctionObject* fo = dynamic_cast<FunctionObject*> (function.getObject()))
{
s.checkTimeOut (location);
DynamicObject::Ptr functionRoot (new DynamicObject());
return fo->invoke (s, args);
static const Identifier thisIdent ("this");
functionRoot->setProperty (thisIdent, thisObject);
for (int i = 0; i < jmin (fo->parameters.size(), arguments.size()); ++i)
functionRoot->setProperty (fo->parameters[i], arguments.getUnchecked(i)->getResult (s));
fo->body->perform (Scope (&s, s.root, functionRoot), &result);
}
else
location.throwError ("This expression is not a function!");
return result;
location.throwError ("This expression is not a function!"); return var();
}
ExpPtr object;
@ -766,6 +761,22 @@ struct JavascriptEngine::RootObject : public DynamicObject
out << "function" << functionCode;
}
var invoke (const Scope& s, const var::NativeFunctionArgs& args) const
{
DynamicObject::Ptr functionRoot (new DynamicObject());
static const Identifier thisIdent ("this");
functionRoot->setProperty (thisIdent, args.thisObject);
const int numArgs = jmin (parameters.size(), args.numArguments);
for (int i = 0; i < numArgs; ++i)
functionRoot->setProperty (parameters.getReference(i), args.arguments[i]);
var result;
body->perform (Scope (&s, s.root, functionRoot), &result);
return result;
}
String functionCode;
Array<Identifier> parameters;
ScopedPointer<Statement> body;
@ -1605,7 +1616,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
};
//==============================================================================
JavascriptEngine::JavascriptEngine() : root (new RootObject())
JavascriptEngine::JavascriptEngine() : maximumExecutionTime (15.0), root (new RootObject())
{
registerNativeObject (RootObject::ObjectClass ::getClassName(), new RootObject::ObjectClass());
registerNativeObject (RootObject::ArrayClass ::getClassName(), new RootObject::ArrayClass());
@ -1617,11 +1628,18 @@ JavascriptEngine::JavascriptEngine() : root (new RootObject())
JavascriptEngine::~JavascriptEngine() {}
Result JavascriptEngine::execute (const String& code, RelativeTime maximumRunTime)
void JavascriptEngine::prepareTimeout() const { root->timeout = Time::getCurrentTime() + maximumExecutionTime; }
void JavascriptEngine::registerNativeObject (Identifier name, DynamicObject* object)
{
root->setProperty (name, object);
}
Result JavascriptEngine::execute (const String& code)
{
try
{
root->timeout = Time::getCurrentTime() + maximumRunTime;
prepareTimeout();
root->execute (code);
}
catch (String& error)
@ -1632,23 +1650,34 @@ Result JavascriptEngine::execute (const String& code, RelativeTime maximumRunTim
return Result::ok();
}
var JavascriptEngine::evaluate (const String& code, Result* message, RelativeTime maximumRunTime)
var JavascriptEngine::evaluate (const String& code, Result* result)
{
try
{
if (message != nullptr) *message = Result::ok();
root->timeout = Time::getCurrentTime() + maximumRunTime;
prepareTimeout();
if (result != nullptr) *result = Result::ok();
return root->evaluate (code);
}
catch (String& error)
{
if (message != nullptr) *message = Result::fail (error);
if (result != nullptr) *result = Result::fail (error);
}
return var::undefined();
}
void JavascriptEngine::registerNativeObject (Identifier name, DynamicObject* object)
var JavascriptEngine::callFunction (Identifier function, const var::NativeFunctionArgs& args, Result* result)
{
root->setProperty (name, object);
try
{
prepareTimeout();
if (result != nullptr) *result = Result::ok();
return root->invoke (function, args);
}
catch (String& error)
{
if (result != nullptr) *result = Result::fail (error);
}
return var::undefined();
}

View file

@ -63,8 +63,7 @@ public:
You can specify a maximum time for which the program is allowed to run, and
it'll return with an error message if this time is exceeded.
*/
Result execute (const String& javascriptCode,
RelativeTime maximumRunTime = RelativeTime::seconds (10));
Result execute (const String& javascriptCode);
/** Attempts to parse and run a javascript expression, and returns the result.
If there's a syntax error, or the expression can't be evaluated, the return value
@ -74,8 +73,15 @@ public:
it'll return with an error message if this time is exceeded.
*/
var evaluate (const String& javascriptCode,
Result* errorMessage = nullptr,
RelativeTime maximumRunTime = RelativeTime::seconds (10));
Result* errorMessage = nullptr);
/** Calls a function in the root namespace, and returns the result.
The function arguments are passed in the same format as used by native
methods in the var class.
*/
var callFunction (Identifier function,
const var::NativeFunctionArgs& args,
Result* errorMessage = nullptr);
/** Adds a native object to the root namespace.
The object passed-in is reference-counted, and will be retained by the
@ -84,9 +90,17 @@ public:
*/
void registerNativeObject (Identifier objectName, DynamicObject* object);
/** This value indicates how long a call to one of the evaluate methods is permitted
to run before timing-out and failing.
The default value is a number of seconds, but you can change this to whatever value
suits your application.
*/
RelativeTime maximumExecutionTime;
private:
struct RootObject;
ReferenceCountedObjectPtr<RootObject> root;
void prepareTimeout() const;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JavascriptEngine)
};