Skip to content

Commit

Permalink
Scripting: Added a utility for calling script functions from native code
Browse files Browse the repository at this point in the history
Makes it easier to call script functions from native code, with
arbitrary parameters passed in the function call. Uses variadic
templates for automatic conversion of native parameters to script
arguments.
  • Loading branch information
skyjake committed Oct 30, 2015
1 parent a851200 commit 5f2ea4f
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 4 deletions.
70 changes: 70 additions & 0 deletions doomsday/sdk/libcore/include/de/scriptsys/process.h
Expand Up @@ -33,6 +33,35 @@ namespace de {

class ArrayValue;

template <typename Type>
QString scriptArgumentAsText(Type const &arg) {
return QString("%1").arg(arg);
}
template <>
inline QString scriptArgumentAsText(QString const &arg) {
if(arg.startsWith("$")) { // Verbatim?
return arg.mid(1);
}
QString quoted(arg);
quoted.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n");
return QString("\"%1\"").arg(quoted);
}
template <>
inline QString scriptArgumentAsText(String const &arg) {
return scriptArgumentAsText(QString(arg));
}
template <>
inline QString scriptArgumentAsText(char const * const &utf8) {
return scriptArgumentAsText(QString::fromUtf8(utf8));
}

inline void convertScriptArguments(QStringList &) {}
template <typename FirstArg, typename... Args>
void convertScriptArguments(QStringList &list, FirstArg const &firstArg, Args... args) {
list << scriptArgumentAsText(firstArg);
convertScriptArguments(list, args...);
}

/**
* Executes a script. The process maintains the execution environment, including things
* like local variables and keeping track of which statement is being executed.
Expand Down Expand Up @@ -210,6 +239,47 @@ class DENG2_PUBLIC Process
*/
Record &locals();

public:
/*
* Utilities for calling script functions from native code.
*/
enum CallResult { IgnoreResult, TakeResult };

/**
* Calls a script function. Native arguments are converted to script
* source text and then parsed into Values when the call is executed.
*
* Only non-named function arguments are supported by this method.
*
* @param result What to do with the result value.
* @param global Global namespace where to execute the call.
* @param function Name of the function.
* @param args Argument values for the function call.
*
* @return Depending on @a result, returns nullptr or the return value
* from the call. Caller gets ownership of the possibly returned Value.
*/
template <typename... Args>
static Value *scriptCall(CallResult result, Record &globals,
String const &function, Args... args)
{
QStringList argsList;
convertScriptArguments(argsList, args...);
Script script(QString("%1(%2)").arg(function).arg(argsList.join(',')));
Process proc(&globals);
proc.run(script);
proc.execute();
if(result == IgnoreResult) return nullptr;
// Return the result using the request value type.
return proc.context().evaluator().popResult();
}

template <typename ReturnValueType, typename... Args>
static ReturnValueType *scriptCall(Record &globals, String const &function, Args... args)
{
return static_cast<ReturnValueType *>(scriptCall(TakeResult, globals, function, args...));
}

private:
DENG2_PRIVATE(d)
};
Expand Down
5 changes: 1 addition & 4 deletions doomsday/sdk/libcore/src/filesys/package.cpp
Expand Up @@ -150,11 +150,8 @@ bool Package::executeFunction(String const &name)
Record &pkgInfo = d->packageInfo();
if(pkgInfo.has(name))
{
Script script(name + "()");
// The global namespace for this function is the package's info namespace.
Process proc(&pkgInfo);
proc.run(script);
proc.execute();
Process::scriptCall(Process::IgnoreResult, pkgInfo, name);
return true;
}
return false;
Expand Down

0 comments on commit 5f2ea4f

Please sign in to comment.