#pragma once #ifndef V8SCRIPTARGUMENTS_H #define V8SCRIPTARGUMENTS_H #include #include #include #include #include "ScriptBindings.h" #include "V8ScriptEnv.h" #include "V8ScriptFunction.h" #include "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()); } }; 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::Argc > 0); SCRIPTENV_D("Invoke Script Argument: %d args\n", base::Argc); if (!base::_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 resolve_args(v8_env, std::index_sequence_for{}); base::_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, _args[0], base::Argc, _args); static_cast(ret); if (try_catch.HasCaught()) { v8_env->ParseErrors(&try_catch); return false; } } else { v8::MaybeLocal ret = cbFunc->Call(context, _args[0], base::Argc, _args); // base::Argc - 1, _args + 1); static_cast(ret); //ret.IsEmpty(); } } SCRIPTENV_D("Finish Script Argument\n"); return true; } private: v8::Local _args[base::Argc]; template inline void resolve_args(V8ScriptEnv *env, std::index_sequence) { if constexpr (sizeof...(Is) > 0) { int unused[] = { ((_args[Is] = detail::ToBinding(env, std::get(base::_tuple))), void(), 0)... }; static_cast(unused); // Avoid warning for unused variable } } }; #endif