/*JSON{ "type":"method", "class": "Function", "name" : "replaceWith", "description" : ["This replaces the function with the one in the argument - while keeping the old function's scope. This allows inner functions to be edited, and is used when edit() is called on an inner function."], "generate" : "jswrap_function_replaceWith", "params" : [ [ "newFunc", "JsVar", "The new function to replace this function with"] ] }*/ void jswrap_function_replaceWith(JsVar *oldFunc, JsVar *newFunc) { if (!jsvIsFunction(newFunc)) { jsWarn("First argument of replaceWith should be a function - ignoring"); return; } // Grab scope - the one thing we want to keep JsVar *scope = jsvFindChildFromString(oldFunc, JSPARSE_FUNCTION_SCOPE_NAME, false); // so now remove all existing entries jsvRemoveAllChildren(oldFunc); // now re-add scope jsvAddName(oldFunc, scope); jsvUnLock(scope); // now re-add other entries JsObjectIterator it; jsvObjectIteratorNew(&it, newFunc); while (jsvObjectIteratorHasElement(&it)) { JsVar *el = jsvObjectIteratorGetKey(&it); jsvObjectIteratorNext(&it); if (!jsvIsStringEqual(el, JSPARSE_FUNCTION_SCOPE_NAME)) { JsVar *copy = jsvCopy(el); if (copy) { jsvAddName(oldFunc, copy); jsvUnLock(copy); } } } jsvObjectIteratorFree(&it); }
/*JSON{ "type" : "method", "class" : "Function", "name" : "replaceWith", "generate" : "jswrap_function_replaceWith", "params" : [ ["newFunc","JsVar","The new function to replace this function with"] ] } This replaces the function with the one in the argument - while keeping the old function's scope. This allows inner functions to be edited, and is used when edit() is called on an inner function. */ void jswrap_function_replaceWith(JsVar *oldFunc, JsVar *newFunc) { if (!jsvIsFunction(newFunc)) { jsWarn("First argument of replaceWith should be a function - ignoring"); return; } // If old was native or vice versa... if (jsvIsNativeFunction(oldFunc) != jsvIsNativeFunction(newFunc)) { if (jsvIsNativeFunction(newFunc)) oldFunc->flags |= JSV_NATIVE; else oldFunc->flags &= ~JSV_NATIVE; } // If old fn started with 'return' or vice versa... if (jsvIsFunctionReturn(oldFunc) != jsvIsFunctionReturn(newFunc)) { if (jsvIsFunctionReturn(newFunc)) oldFunc->flags = (oldFunc->flags&~JSV_VARTYPEMASK) |JSV_FUNCTION_RETURN; else oldFunc->flags = (oldFunc->flags&~JSV_VARTYPEMASK) |JSV_FUNCTION; } // Grab scope - the one thing we want to keep JsVar *scope = jsvFindChildFromString(oldFunc, JSPARSE_FUNCTION_SCOPE_NAME, false); // so now remove all existing entries jsvRemoveAllChildren(oldFunc); // now re-add scope if (scope) jsvAddName(oldFunc, scope); jsvUnLock(scope); // now re-add other entries JsvObjectIterator it; jsvObjectIteratorNew(&it, newFunc); while (jsvObjectIteratorHasValue(&it)) { JsVar *el = jsvObjectIteratorGetKey(&it); jsvObjectIteratorNext(&it); if (!jsvIsStringEqual(el, JSPARSE_FUNCTION_SCOPE_NAME)) { JsVar *copy = jsvCopy(el); if (copy) { jsvAddName(oldFunc, copy); jsvUnLock(copy); } } jsvUnLock(el); } jsvObjectIteratorFree(&it); }
/*JSON{ "type":"method", "class": "Object", "name" : "clone", "description" : "Copy this object completely", "generate" : "jswrap_object_clone", "return" : ["JsVar", "A copy of this Object"] }*/ JsVar *jswrap_object_clone(JsVar *parent) { return jsvCopy(parent); }
/*JSON{ "type" : "method", "class" : "Function", "name" : "bind", "generate" : "jswrap_function_bind", "params" : [ ["this","JsVar","The value to use as the 'this' argument when executing the function"], ["params","JsVarArray","Optional Default parameters that are prepended to the call"] ], "return" : ["JsVar","The 'bound' function"] } This executes the function with the supplied 'this' argument and parameters */ JsVar *jswrap_function_bind(JsVar *parent, JsVar *thisArg, JsVar *argsArray) { if (!jsvIsFunction(parent)) { jsExceptionHere(JSET_TYPEERROR, "Function.bind expects to be called on function, got %t", parent); return 0; } JsVar *fn; if (jsvIsNativeFunction(parent)) fn = jsvNewNativeFunction(parent->varData.native.ptr, parent->varData.native.argTypes); else fn = jsvNewWithFlags(jsvIsFunctionReturn(parent) ? JSV_FUNCTION_RETURN : JSV_FUNCTION); if (!fn) return 0; // Old function info JsvObjectIterator fnIt; jsvObjectIteratorNew(&fnIt, parent); // add previously bound arguments while (jsvObjectIteratorHasValue(&fnIt)) { JsVar *param = jsvObjectIteratorGetKey(&fnIt); JsVar *defaultValue = jsvObjectIteratorGetValue(&fnIt); bool wasBound = jsvIsFunctionParameter(param) && defaultValue; if (wasBound) { JsVar *newParam = jsvCopy(param); if (newParam) { // could be out of memory jsvAddName(fn, newParam); jsvUnLock(newParam); } } jsvUnLock2(param, defaultValue); if (!wasBound) break; jsvObjectIteratorNext(&fnIt); } // add bound arguments JsvObjectIterator argIt; jsvObjectIteratorNew(&argIt, argsArray); while (jsvObjectIteratorHasValue(&argIt)) { JsVar *defaultValue = jsvObjectIteratorGetValue(&argIt); bool addedParam = false; while (!addedParam && jsvObjectIteratorHasValue(&fnIt)) { JsVar *param = jsvObjectIteratorGetKey(&fnIt); if (!jsvIsFunctionParameter(param)) { jsvUnLock(param); break; } JsVar *newParam = jsvCopyNameOnly(param, false, true); jsvSetValueOfName(newParam, defaultValue); jsvAddName(fn, newParam); addedParam = true; jsvUnLock2(param, newParam); jsvObjectIteratorNext(&fnIt); } if (!addedParam) { JsVar *paramName = jsvNewFromEmptyString(); if (paramName) { jsvMakeFunctionParameter(paramName); // force this to be called a function parameter jsvSetValueOfName(paramName, defaultValue); jsvAddName(fn, paramName); jsvUnLock(paramName); } } jsvUnLock(defaultValue); jsvObjectIteratorNext(&argIt); } jsvObjectIteratorFree(&argIt); // Copy the rest of the old function's info while (jsvObjectIteratorHasValue(&fnIt)) { JsVar *param = jsvObjectIteratorGetKey(&fnIt); JsVar *newParam = jsvCopyNameOnly(param, true, true); if (newParam) { // could be out of memory jsvAddName(fn, newParam); jsvUnLock(newParam); } jsvUnLock(param); jsvObjectIteratorNext(&fnIt); } jsvObjectIteratorFree(&fnIt); // Add 'this' jsvObjectSetChild(fn, JSPARSE_FUNCTION_THIS_NAME, thisArg); // no unlock needed return fn; }