#ifndef V8SCRIPTARGUMENTS_H #define V8SCRIPTARGUMENTS_H #include #include #include #include #include "scripting/interface/ScriptBindings.h" #include "scripting/v8/V8ScriptEnv.h" #include "scripting/v8/V8ScriptFunction.h" #include "scripting/v8/V8ScriptObject.h" namespace detail { inline v8::Handle toBinding(V8ScriptEnv* env, std::nullptr_t val) { return v8::Null(env->isolate()); } inline v8::Handle toBinding(V8ScriptEnv* env, double val) { return v8::Number::New(env->isolate(), val); } inline v8::Handle toBinding(V8ScriptEnv* env, int val) { return v8::Integer::New(env->isolate(), val); } inline v8::Handle toBinding(V8ScriptEnv* env, const std::string& val) { return v8::String::NewFromUtf8(env->isolate(), val.c_str()).ToLocalChecked(); } inline v8::Handle toBinding(V8ScriptEnv* env, const std::shared_ptr& object) { return object.get()->object(); } inline v8::Handle toBinding(V8ScriptEnv* env, IScriptFunction* function) { return static_cast(function)->function(); } template inline v8::Handle toBinding(V8ScriptEnv* env, IScriptObject* val) { V8ScriptObject* wrappedVal = static_cast*>(val); wrappedVal->decreaseReference(); return wrappedVal->handle(env->isolate()); } }; // namespace detail template class V8ScriptArguments : public ScriptArguments { typedef ScriptArguments base; public: template explicit V8ScriptArguments(Args&&... An) : ScriptArguments(std::forward(An)...) { } ~V8ScriptArguments() = default; virtual bool invoke(IScriptFunction* func, bool catchExceptions = false) override { assert(base::m_argc > 0); SCRIPTENV_D("Invoke Script Argument: %d args\n", base::m_argc); if (!base::m_resolved) { V8ScriptFunction* v8_func = static_cast(func); V8ScriptEnv* v8_env = static_cast(v8_func->env()); v8::Isolate* isolate = v8_env->isolate(); v8::Local context = v8_env->context(); // get a v8 handle for the function to be executed v8::Local cbFunc = v8_func->function(); assert(!cbFunc.IsEmpty()); // sort arguments into array resolveArgs(v8_env, std::index_sequence_for{}); base::m_resolved = true; // TODO(joey): This will probably not stay like this. Needed the trycatch for executing // new objects for the first time only. Will figure something out. // call function if (catchExceptions) { v8::TryCatch try_catch(isolate); v8::MaybeLocal ret = cbFunc->Call(context, m_args[0], base::m_argc, m_args); static_cast(ret); if (try_catch.HasCaught()) { v8_env->parseErrors(&try_catch); return false; } } else { v8::MaybeLocal ret = cbFunc->Call(context, m_args[0], base::m_argc, m_args); // base::Argc - 1, m_args + 1); static_cast(ret); //ret.IsEmpty(); } } SCRIPTENV_D("Finish Script Argument\n"); return true; } private: v8::Local m_args[base::m_argc]; template inline void resolveArgs(V8ScriptEnv* env, std::index_sequence) { if constexpr (sizeof...(Is) > 0) { int unused[] = { ((m_args[Is] = detail::toBinding(env, std::get(base::m_tuple))), void(), 0)... }; static_cast(unused); // Avoid warning for unused variable } } }; #endif