Example #1
0
/*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);

}
Example #2
0
/*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;
}
Example #3
0
/* This is like jsfGetJSONWithCallback, but handles ONLY functions (and does not print the initial 'function' text) */
void jsfGetJSONForFunctionWithCallback(JsVar *var, JSONFlags flags, vcbprintf_callback user_callback, void *user_data) {
  assert(jsvIsFunction(var));
  JsVar *codeVar = 0; // TODO: this should really be in jsvAsString

  JsvObjectIterator it;
  jsvObjectIteratorNew(&it, var);

  bool firstParm = true;
  cbprintf(user_callback, user_data, "(");
  while (jsvObjectIteratorHasValue(&it)) {
    JsVar *child = jsvObjectIteratorGetKey(&it);
    if (jsvIsFunctionParameter(child)) {
      if (firstParm)
        firstParm=false;
      else
        cbprintf(user_callback, user_data, ",");
      JsVar *name = jsvNewFromStringVar(child, 1, JSVAPPENDSTRINGVAR_MAXLENGTH);
      cbprintf(user_callback, user_data, "%v", name);
      jsvUnLock(name);
    } else if (jsvIsString(child) && jsvIsStringEqual(child, JSPARSE_FUNCTION_CODE_NAME)) {
      codeVar = jsvObjectIteratorGetValue(&it);
    }
    jsvUnLock(child);
    jsvObjectIteratorNext(&it);
  }
  jsvObjectIteratorFree(&it);
  cbprintf(user_callback, user_data, ") ");

  if (jsvIsNative(var)) {
    cbprintf(user_callback, user_data, "{ [native code] }");
  } else {
    if (codeVar) {
      if (flags & JSON_LIMIT) {
        cbprintf(user_callback, user_data, "{%s}", JSON_LIMIT_TEXT);
      } else {
        bool hasNewLine = jsvGetStringIndexOf(codeVar,'\n')>=0;
        user_callback(hasNewLine?"{\n  ":"{", user_data);
        if (jsvIsFunctionReturn(var))
          user_callback("return ", user_data);
        // reconstruct the tokenised output into something more readable
        char buf[32];
        unsigned char lastch = 0;
        JsvStringIterator it;
        jsvStringIteratorNew(&it, codeVar, 0);
        while (jsvStringIteratorHasChar(&it)) {
          unsigned char ch = (unsigned char)jsvStringIteratorGetChar(&it);
          if (jslNeedSpaceBetween(lastch, ch))
            user_callback(" ", user_data);
          jslFunctionCharAsString(ch, buf, sizeof(buf));
          user_callback(buf, user_data);
          jsvStringIteratorNext(&it);
          lastch = ch;
        }
        jsvStringIteratorFree(&it);

        user_callback(hasNewLine?"\n}":"}", user_data);
      }
    } else cbprintf(user_callback, user_data, "{}");
  }
  jsvUnLock(codeVar);
}