// This file is part of VSTGUI. It is subject to the license terms // in the LICENSE file found in the top-level directory of this // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE #pragma once #include "../tiny-js/TinyJS.h" //------------------------------------------------------------------------ namespace VSTGUI { namespace ScriptingInternal { //------------------------------------------------------------------------ struct ScriptAddChildScoped { using CScriptVar = TJS::CScriptVar; using CScriptVarLink = TJS::CScriptVarLink; ScriptAddChildScoped (CScriptVar& var, std::string_view name, CScriptVar* obj) : var (var) { if ((link = var.findChild (name))) { oldVar = TJS::owning (link->getVar ()); link->setVar (obj); } else { link = var.addChild (name, obj); } } ~ScriptAddChildScoped () noexcept { if (oldVar && link) { link->setVar (oldVar); oldVar->release (); } else if (link) { var.removeLink (link); } } private: CScriptVar& var; CScriptVarLink* link {nullptr}; CScriptVar* oldVar {nullptr}; }; //------------------------------------------------------------------------ inline TJS::CScriptVar* createJSFunction (TJS::JSCallback&& proc) { auto funcVar = new TJS::CScriptVar (TJS::TINYJS_BLANK_DATA, TJS::SCRIPTVAR_FUNCTION | TJS::SCRIPTVAR_NATIVE); funcVar->setCallback (std::move (proc)); return funcVar; } //------------------------------------------------------------------------ inline TJS::CScriptVar* createJSFunction (TJS::JSCallback&& proc, const std::initializer_list& argNames) { auto f = createJSFunction (std::move (proc)); for (auto name : argNames) f->addChildNoDup (name); return f; } //------------------------------------------------------------------------ inline TJS::CScriptVar* getArgument (TJS::CScriptVar* var, std::string_view argName, std::string_view funcSignature) { auto child = var->findChild (argName); auto result = child ? child->getVar () : nullptr; if (!result || result->isUndefined ()) { TJS::string s ("Missing `"); s.append (argName); s.append ("` argument in "); s.append (funcSignature); throw TJS::CScriptException (std::move (s)); } return result; } //------------------------------------------------------------------------ inline TJS::CScriptVar* getOptionalArgument (TJS::CScriptVar* var, std::string_view argName) { if (auto child = var->findChild (argName)) return child->getVar (); return nullptr; } //------------------------------------------------------------------------ struct ScriptObject { using CScriptVar = TJS::CScriptVar; ScriptObject () { scriptVar = TJS::owning (new CScriptVar ()); } ScriptObject (CScriptVar* var) : scriptVar (TJS::owning (var)) {} ScriptObject (ScriptObject&& o) { *this = std::move (o); } ScriptObject& operator= (ScriptObject&& o) { if (scriptVar) scriptVar->release (); scriptVar = nullptr; std::swap (scriptVar, o.scriptVar); return *this; } virtual ~ScriptObject () noexcept { if (scriptVar) { scriptVar->release (); } } operator CScriptVar* () const { validate (); return scriptVar; } CScriptVar* operator->() const { validate (); return scriptVar; } CScriptVar* getVar () const { validate (); return scriptVar; } CScriptVar* take () { auto v = scriptVar; scriptVar = nullptr; return v; } void addChild (std::string_view name, ScriptObject&& obj) { validate (); scriptVar->addChild (name, obj); } void addChild (std::string_view name, double d) { validate (); scriptVar->addChild (name, new CScriptVar (d)); } void addChild (std::string_view name, int64_t i) { validate (); scriptVar->addChild (name, new CScriptVar (i)); } void addChild (std::string_view name, int32_t i) { validate (); scriptVar->addChild (name, new CScriptVar (static_cast (i))); } void addChild (std::string_view name, std::string_view value) { validate (); scriptVar->addChild (name, new CScriptVar (TJS::string {value.data (), value.size ()})); } void addFunc (std::string_view name, std::function&& func) { validate (); scriptVar->addChild (name, createJSFunction (std::move (func))); } void addFunc (std::string_view name, std::function&& func, const std::initializer_list& argNames) { validate (); scriptVar->addChild (name, createJSFunction (std::move (func), argNames)); } void addFunc (std::string_view name, std::string_view code) { validate (); auto funcVar = new TJS::CScriptVar (TJS::TINYJS_BLANK_DATA, TJS::SCRIPTVAR_FUNCTION); funcVar->setFunctionScript (code); scriptVar->addChild (name, funcVar); } using OnDestroyFunc = std::function; void setOnDestroy (OnDestroyFunc&& f) { validate (); scriptVar->setLifeTimeObserver (OnDestroy::make (std::move (f))); } protected: struct OnDestroy : TJS::IScriptVarLifeTimeObserver { static OnDestroy* make (OnDestroyFunc f) { return new OnDestroy (std::move (f)); } private: OnDestroy (OnDestroyFunc f) : func (std::move (f)) {} void onDestroy (CScriptVar* var) { func (var); delete this; } OnDestroyFunc func; }; void validate () const { if (scriptVar == nullptr) scriptVar = TJS::owning (new CScriptVar ()); } mutable CScriptVar* scriptVar {nullptr}; }; //------------------------------------------------------------------------ } // ScriptingInternal } // VSTGUI