示例#1
0
JsVar *jswrap_http_createServer(JsVar *callback) {
  JsVar *skippedCallback = jsvSkipName(callback);
  if (!jsvIsFunction(skippedCallback)) {
    jsError("Expecting Callback Function but got %t", skippedCallback);
    jsvUnLock(skippedCallback);
    return 0;
  }
  jsvUnLock(skippedCallback);
  return httpServerNew(callback);
}
示例#2
0
/*JSON{
  "type" : "constructor",
  "class" : "Object",
  "name" : "Object",
  "generate" : "jswrap_object_constructor",
  "params" : [
    ["value","JsVar","A single value to be converted to an object"]
  ],
  "return" : ["JsVar","An Object"]
}
Creates an Object from the supplied argument
 */
JsVar *jswrap_object_constructor(JsVar *value) {
  if (jsvIsObject(value) || jsvIsArray(value) || jsvIsFunction(value))
    return jsvLockAgain(value);
  const char *objName = jswGetBasicObjectName(value);
  JsVar *funcName = objName ? jspGetNamedVariable(objName) : 0;
  if (!funcName) return jsvNewObject();
  JsVar *func = jsvSkipName(funcName);
  JsVar *result = jspeFunctionCall(func, funcName, 0, false, 1, &value);
  jsvUnLock2(funcName, func);
  return result;
}
示例#3
0
/*JSON{ "type":"function", "name" : "edit",
        "description" : ["Fill the console with the contents of the given function, so you can edit it.",
                         "NOTE: This is a convenience function - it will not edit 'inner functions'. For that, you must edit the 'outer function' and re-execute it."],
        "generate" : "jswrap_interface_edit",
        "params" : [ [ "funcName", "JsVar", "The name of the function to edit (either a string or just the unquoted name)"] ]
}*/
void jswrap_interface_edit(JsVar *funcName) {
  JsVar *func = 0;
  if (jsvIsString(funcName)) {
    funcName = jsvLockAgain(funcName);
    func = jsvSkipNameAndUnLock(jsvFindChildFromVar(execInfo.root, funcName, 0));
  } else {
    func = funcName;
    funcName = jsvGetPathTo(execInfo.root, func, 2);
  }

  if (jsvIsString(funcName)) {
    if (jsvIsFunction(func)) {
      JsVar *scopeVar = jsvFindChildFromString(func, JSPARSE_FUNCTION_SCOPE_NAME, false);
      JsVar *inRoot = jsvGetArrayIndexOf(execInfo.root, func, true);
      bool normalDecl = scopeVar==0 && inRoot!=0;
      jsvUnLock(inRoot);
      jsvUnLock(scopeVar);
      JsVar *newLine = jsvNewFromEmptyString();
      if (newLine) { // could be out of memory
        /* normalDecl:
         *
         * function foo() { ... }
         *
         * NOT normalDecl:
         *
         * foo.replaceWith(function() { ... });
         *
         */
        JsVar *funcData = jsvAsString(func, false);

        if (normalDecl) {
          jsvAppendString(newLine, "function ");
          jsvAppendStringVarComplete(newLine, funcName);
          jsvAppendStringVar(newLine, funcData, 9, JSVAPPENDSTRINGVAR_MAXLENGTH);

        } else {
          jsvAppendStringVarComplete(newLine, funcName);
          jsvAppendString(newLine, ".replaceWith(");
          jsvAppendStringVarComplete(newLine, funcData);
          jsvAppendString(newLine, ");");
        }
        jsvUnLock(funcData);
        jsiReplaceInputLine(newLine);
        jsvUnLock(newLine);
      }
    } else {
      jsError("Edit should be called with the name of a function");
    }
  } else {
    jsError("Edit should be called with edit(funcName) or edit('funcName')");
  }
  jsvUnLock(func);
  jsvUnLock(funcName);
}
示例#4
0
void jsvIteratorNew(JsvIterator *it, JsVar *obj) {
  if (jsvIsArray(obj) || jsvIsObject(obj) || jsvIsFunction(obj)) {
    it->type = JSVI_OBJECT;
    jsvObjectIteratorNew(&it->it.obj, obj);
  } else if (jsvIsArrayBuffer(obj)) {
    it->type = JSVI_ARRAYBUFFER;
    jsvArrayBufferIteratorNew(&it->it.buf, obj, 0);
  } else if (jsvHasCharacterData(obj)) {
    it->type = JSVI_STRING;
    jsvStringIteratorNew(&it->it.str, obj, 0);
  } else assert(0);
}
示例#5
0
/*JSON{
  "type" : "method",
  "class" : "ArrayBufferView",
  "name" : "map",
  "generate" : "jswrap_arraybufferview_map",
  "params" : [
    ["function","JsVar","Function used to map one item to another"],
    ["thisArg","JsVar","if specified, the function is called with 'this' set to thisArg (optional)"]
  ],
  "return" : ["JsVar","An array containing the results"],
  "return_object" : "ArrayBufferView"
}
Return an array which is made from the following: ```A.map(function) = [function(A[0]), function(A[1]), ...]```

**Note:** This returns an ArrayBuffer of the same type it was called on. To get an Array, use `Array.prototype.map`
*/
JsVar *jswrap_arraybufferview_map(JsVar *parent, JsVar *funcVar, JsVar *thisVar) {
  if (!jsvIsArrayBuffer(parent)) {
    jsExceptionHere(JSET_ERROR, "ArrayBufferView.map can only be called on an ArrayBufferView");
    return 0;
  }
  if (!jsvIsFunction(funcVar)) {
    jsExceptionHere(JSET_ERROR, "ArrayBufferView.map's first argument should be a function");
    return 0;
  }
  if (!jsvIsUndefined(thisVar) && !jsvIsObject(thisVar)) {
    jsExceptionHere(JSET_ERROR, "ArrayBufferView.map's second argument should be undefined, or an object");
    return 0;
  }

  // create ArrayBuffer result
  JsVarDataArrayBufferViewType arrayBufferType = parent->varData.arraybuffer.type;
  JsVar *arrayBufferLength = jsvNewFromInteger((JsVarInt)jsvGetArrayBufferLength(parent));
  JsVar *array = jswrap_typedarray_constructor(arrayBufferType, arrayBufferLength, 0, 0);
  jsvUnLock(arrayBufferLength);
  if (!array) return 0;

  // now iterate
  JsvIterator it; // TODO: if we really are limited to ArrayBuffers, this could be an ArrayBufferIterator.
  jsvIteratorNew(&it, parent);
  JsvArrayBufferIterator itdst;
  jsvArrayBufferIteratorNew(&itdst, array, 0);

  while (jsvIteratorHasElement(&it)) {
    JsVar *index = jsvIteratorGetKey(&it);
    if (jsvIsInt(index)) {
      JsVarInt idxValue = jsvGetInteger(index);

      JsVar *args[3], *mapped;
      args[0] = jsvIteratorGetValue(&it);
      args[1] = jsvNewFromInteger(idxValue); // child is a variable name, create a new variable for the index
      args[2] = parent;
      mapped = jspeFunctionCall(funcVar, 0, thisVar, false, 3, args);
      jsvUnLock(args[0]);
      jsvUnLock(args[1]);
      if (mapped) {
        jsvArrayBufferIteratorSetValue(&itdst, mapped);
        jsvUnLock(mapped);
      }
    }
    jsvUnLock(index);
    jsvIteratorNext(&it);
    jsvArrayBufferIteratorNext(&itdst);
  }
  jsvIteratorFree(&it);
  jsvArrayBufferIteratorFree(&itdst);

  return array;
}
示例#6
0
JsVar *_jswrap_array_map_or_forEach(JsVar *parent, JsVar *funcVar, JsVar *thisVar, bool isMap) {
  const char *name = isMap ? "map":"forEach";
  if (!jsvIsIterable(parent)) {
    jsError("Array.%s can only be called on something iterable", name);
    return 0;
  }
  if (!jsvIsFunction(funcVar)) {
    jsError("Array.%s's first argument should be a function", name);
    return 0;
  }
  if (!jsvIsUndefined(thisVar) && !jsvIsObject(thisVar)) {
    jsError("Array.%s's second argument should be undefined, or an object", name);
    return 0;
  }
  JsVar *array = 0;
  if (isMap)
    array = jsvNewWithFlags(JSV_ARRAY);
  if (array || !isMap) {
    JsvIterator it;
    jsvIteratorNew(&it, parent);
    while (jsvIteratorHasElement(&it)) {
      JsVar *index = jsvIteratorGetKey(&it);
      if (jsvIsInt(index)) {
        JsVarInt idxValue = jsvGetInteger(index);

        JsVar *args[3], *mapped;
        args[0] = jsvIteratorGetValue(&it);
        args[1] = jsvNewFromInteger(idxValue); // child is a variable name, create a new variable for the index
        args[2] = parent;
        mapped = jspeFunctionCall(funcVar, 0, thisVar, false, 3, args);
        jsvUnLock(args[0]);
        jsvUnLock(args[1]);
        if (mapped) {
          if (isMap) {
            JsVar *name = jsvNewFromInteger(idxValue);
            if (name) { // out of memory?
              jsvMakeIntoVariableName(name, mapped);
              jsvAddName(array, name);
              jsvUnLock(name);
            }
          }
          jsvUnLock(mapped);
        }
      }
      jsvUnLock(index);
      jsvIteratorNext(&it);
    }
    jsvIteratorFree(&it);
  }
  return array;
}
示例#7
0
/*JSON{
  "type" : "method",
  "class" : "Array",
  "name" : "reduce",
  "ifndef" : "SAVE_ON_FLASH",
  "generate" : "jswrap_array_reduce",
  "params" : [
    ["callback","JsVar","Function used to reduce the array"],
    ["initialValue","JsVar","if specified, the initial value to pass to the function"]
  ],
  "return" : ["JsVar","The value returned by the last function called"]
}
Execute `previousValue=initialValue` and then `previousValue = callback(previousValue, currentValue, index, array)` for each element in the array, and finally return previousValue.
*/
JsVar *jswrap_array_reduce(JsVar *parent, JsVar *funcVar, JsVar *initialValue) {
  const char *name = "reduce";
  if (!jsvIsIterable(parent)) {
    jsExceptionHere(JSET_ERROR, "Array.%s can only be called on something iterable", name);
    return 0;
  }
  if (!jsvIsFunction(funcVar)) {
    jsExceptionHere(JSET_ERROR, "Array.%s's first argument should be a function", name);
    return 0;
  }
  JsVar *previousValue = initialValue ? jsvLockAgain(initialValue) : 0;
  JsvIterator it;
  jsvIteratorNew(&it, parent);
  if (!previousValue) {
    bool isDone = false;
    while (!isDone && jsvIteratorHasElement(&it)) {
      JsVar *index = jsvIteratorGetKey(&it);
      if (jsvIsInt(index)) {
        previousValue = jsvIteratorGetValue(&it);
        isDone = true;
      }
      jsvUnLock(index);
      jsvIteratorNext(&it);
    }
    if (!previousValue) {
      jsExceptionHere(JSET_ERROR, "Array.%s without initial value required non-empty array", name);
    }
  }
  while (jsvIteratorHasElement(&it)) {
    JsVar *index = jsvIteratorGetKey(&it);
    if (jsvIsInt(index)) {
      JsVarInt idxValue = jsvGetInteger(index);

      JsVar *args[4];
      args[0] = previousValue;
      args[1] = jsvIteratorGetValue(&it);
      args[2] = jsvNewFromInteger(idxValue); // child is a variable name, create a new variable for the index
      args[3] = parent;
      previousValue = jspeFunctionCall(funcVar, 0, 0, false, 4, args);
      jsvUnLock(args[0]);
      jsvUnLock(args[1]);
      jsvUnLock(args[2]);
    }
    jsvUnLock(index);
    jsvIteratorNext(&it);
  }
  jsvIteratorFree(&it);

  return previousValue;
}
示例#8
0
/*JSON{
  "type"     : "staticmethod",
  "class"    : "ESP8266WiFi",
  "name"     : "ping",
  "generate" : "jswrap_ESP8266WiFi_ping",
  "params"   : [
    ["ipAddr","JsVar","A string or integer representation of an IP address."],
    ["pingCallback", "JsVar", "Optional callback function."]
  ]
}*/
void jswrap_ESP8266WiFi_ping(
    JsVar *ipAddr,      //!< A string or integer representation of an IP address.
    JsVar *pingCallback //!< Optional callback function.
  ) {
  // If the parameter is a string, get the IP address from the string
  // representation.
  if (jsvIsString(ipAddr)) {
    char ipString[20];
    int len = jsvGetString(ipAddr, ipString, sizeof(ipString)-1);
    ipString[len] = '\0';
    pingOpt.ip = networkParseIPAddress(ipString);
    if (pingOpt.ip == 0) {
        jsExceptionHere(JSET_ERROR, "Not a valid IP address.");
      return;
    }
  } else
  // If the parameter is an integer, treat it as an IP address.
  if (jsvIsInt(ipAddr)) {
    pingOpt.ip = jsvGetInteger(ipAddr);
  } else
  // The parameter was neither a string nor an IP address and hence we don't
  // know how to get the IP address of the partner to ping so throw an
  // exception.
  {
      jsExceptionHere(JSET_ERROR, "IP address must be string or integer.");
    return;
  }

  if (jsvIsUndefined(pingCallback) || jsvIsNull(pingCallback)) {
    if (g_jsPingCallback != NULL) {
      jsvUnLock(g_jsPingCallback);
    }
    g_jsPingCallback = NULL;
  } else if (!jsvIsFunction(pingCallback)) {
      jsExceptionHere(JSET_ERROR, "Callback is not a function.");
    return;
  } else {
    if (g_jsPingCallback != NULL) {
      jsvUnLock(g_jsPingCallback);
    }
    g_jsPingCallback = pingCallback;
    jsvLockAgainSafe(g_jsPingCallback);
  }

  // We now have an IP address to ping ... so ping.
  memset(&pingOpt, 0, sizeof(pingOpt));
  pingOpt.count = 5;
  pingOpt.recv_function = pingRecvCB;
  ping_start(&pingOpt);
}
/*JSON{ "type":"method", "class": "Serial", "name" : "onData",
         "description" : ["When a character is received on this serial port, the function supplied to onData gets called.",
                          "Only one function can ever be supplied, so calling onData(undefined) will stop any function being called"],
         "generate" : "jswrap_serial_onData",
         "params" : [ [ "function", "JsVarName", "A function to call when data arrives. It takes one argument, which is an object with a 'data' field"] ]
}*/
void jswrap_serial_onData(JsVar *parent, JsVar *funcVar) {
  JsVar *skippedFunc = jsvSkipName(funcVar);
  if (!jsvIsFunction(skippedFunc) && !jsvIsString(skippedFunc)) {
    jsiConsolePrint("Function or String not supplied - removing onData handler.\n");
    JsVar *handler = jsvFindChildFromString(parent, USART_CALLBACK_NAME, false);
    if (handler) {
      jsvRemoveChild(parent, handler);
      jsvUnLock(handler);
    }
  } else {
    jsvUnLock(jsvSetNamedChild(parent, funcVar, USART_CALLBACK_NAME));
  }
  jsvUnLock(skippedFunc);
}
示例#10
0
/*JSON{
  "type" : "method",
  "class" : "WLAN",
  "name" : "connect",
  "generate" : "jswrap_wlan_connect",
  "params" : [
    ["ap","JsVar","Access point name"],
    ["key","JsVar","WPA2 key (or undefined for unsecured connection)"],
    ["callback","JsVar","Function to call back with connection status. It has one argument which is one of 'connect'/'disconnect'/'dhcp'"]
  ],
  "return" : ["bool","True if connection succeeded, false if it didn't."]
}
Connect to a wireless network
*/
bool jswrap_wlan_connect(JsVar *wlanObj, JsVar *vAP, JsVar *vKey, JsVar *callback) {
  if (!(jsvIsUndefined(callback) || jsvIsFunction(callback))) {
    jsError("Expecting callback Function but got %t", callback);
    return 0;
  }

  JsNetwork net;
  if (!networkGetFromVar(&net)) return false;

  // if previously completely disconnected, try and reconnect
  if (jsvGetBoolAndUnLock(jsvObjectGetChild(wlanObj,JS_HIDDEN_CHAR_STR"DIS",0))) {
    cc3000_initialise(wlanObj);
    jsvObjectSetChildAndUnLock(wlanObj,JS_HIDDEN_CHAR_STR"DIS", jsvNewFromBool(false));
  }

  if (jsvIsFunction(callback)) {
    jsvObjectSetChild(wlanObj, CC3000_ON_STATE_CHANGE, callback);
  }

  jsvObjectSetChild(wlanObj,JS_HIDDEN_CHAR_STR"AP", vAP); // no unlock intended
  jsvObjectSetChild(wlanObj,JS_HIDDEN_CHAR_STR"KEY", vKey); // no unlock intended

  char ap[32];
  char key[32];
  unsigned long security = WLAN_SEC_UNSEC;
  jsvGetString(vAP, ap, sizeof(ap));
  if (jsvIsString(vKey)) {
    security = WLAN_SEC_WPA2;
    jsvGetString(vKey, key, sizeof(key));
  }
  // might want to set wlan_ioctl_set_connection_policy
  bool connected =  wlan_connect(security, ap, (long)strlen(ap), NULL, (unsigned char*)key, (long)strlen(key))==0;

  networkFree(&net);
  // note that we're only online (for networkState) when DHCP succeeds
  return connected;
}
示例#11
0
/*JSON{
  "type" : "method",
  "class" : "Object",
  "name" : "on",
  "generate" : "jswrap_object_on",
  "params" : [
    ["event","JsVar","The name of the event, for instance 'data'"],
    ["listener","JsVar","The listener to call when this event is received"]
  ]
}
Register an event listener for this object, for instance ```http.on('data', function(d) {...})```. See Node.js's EventEmitter.
 */
void jswrap_object_on(JsVar *parent, JsVar *event, JsVar *listener) {
  if (!jsvHasChildren(parent)) {
    jsWarn("Parent must be an object - not a String, Integer, etc.");
    return;
  }
  if (!jsvIsString(event)) {
    jsWarn("First argument to EventEmitter.on(..) must be a string");
    return;
  }
  if (!jsvIsFunction(listener) && !jsvIsString(listener)) {
    jsWarn("Second argument to EventEmitter.on(..) must be a function or a String (containing code)");
    return;
  }

  JsVar *eventName = jsvVarPrintf(JS_EVENT_PREFIX"%s",event);
  if (!eventName) return; // no memory

  JsVar *eventList = jsvFindChildFromVar(parent, eventName, true);
  jsvUnLock(eventName);
  JsVar *eventListeners = jsvSkipName(eventList);
  if (jsvIsUndefined(eventListeners)) {
    // just add
    jsvSetValueOfName(eventList, listener);
  } else {
    if (jsvIsArray(eventListeners)) {
      // we already have an array, just add to it
      jsvArrayPush(eventListeners, listener);
    } else {
      // not an array - we need to make it an array
      JsVar *arr = jsvNewEmptyArray();
      jsvArrayPush(arr, eventListeners);
      jsvArrayPush(arr, listener);
      jsvSetValueOfName(eventList, arr);
      jsvUnLock(arr);
    }
  }
  jsvUnLock2(eventListeners, eventList);
  /* Special case if we're a data listener and data has already arrived then
   * we queue an event immediately. */
  if (jsvIsStringEqual(event, "data")) {
    JsVar *buf = jsvObjectGetChild(parent, STREAM_BUFFER_NAME, 0);
    if (jsvIsString(buf)) {
      jsiQueueObjectCallbacks(parent, STREAM_CALLBACK_NAME, &buf, 1);
      jsvRemoveNamedChild(parent, STREAM_BUFFER_NAME);
    }
    jsvUnLock(buf);
  }
}
示例#12
0
/*JSON{
  "type" : "property",
  "class" : "Object",
  "name" : "length",
  "generate" : "jswrap_object_length",
  "return" : ["JsVar","The length of the object"]
}
Find the length of the object
 */
JsVar *jswrap_object_length(JsVar *parent) {
  JsVarInt l;
  if (jsvIsArray(parent)) {
    l = jsvGetArrayLength(parent);
  } else if (jsvIsArrayBuffer(parent)) {
    l = (JsVarInt)jsvGetArrayBufferLength(parent);
  } else if (jsvIsString(parent)) {
    l = (JsVarInt)jsvGetStringLength(parent);
  } else if (jsvIsFunction(parent)) {
    JsVar *args = jsvGetFunctionArgumentLength(parent);
    l = jsvGetArrayLength(args);
    jsvUnLock(args);
  } else
    return 0;
  return jsvNewFromInteger(l);
}
示例#13
0
/*JSON{
  "type" : "method",
  "class" : "Object",
  "name" : "on",
  "generate" : "jswrap_object_on",
  "params" : [
    ["event","JsVar","The name of the event, for instance 'data'"],
    ["listener","JsVar","The listener to call when this event is received"]
  ]
}
Register an event listener for this object, for instance ```http.on('data', function(d) {...})```. See Node.js's EventEmitter.
*/
void jswrap_object_on(JsVar *parent, JsVar *event, JsVar *listener) {
  if (!jsvIsObject(parent)) {
      jsWarn("Parent must be a proper object - not a String, Integer, etc.");
      return;
    }
  if (!jsvIsString(event)) {
      jsWarn("First argument to EventEmitter.on(..) must be a string");
      return;
    }
  if (!jsvIsFunction(listener) && !jsvIsString(listener)) {
    jsWarn("Second argument to EventEmitter.on(..) must be a function or a String (containing code)");
    return;
  }
  char eventName[16] = "#on";
  jsvGetString(event, &eventName[3], sizeof(eventName)-4);

  JsVar *eventList = jsvFindChildFromString(parent, eventName, true);
  JsVar *eventListeners = jsvSkipName(eventList);
  if (jsvIsUndefined(eventListeners)) {
    // just add
    jsvSetValueOfName(eventList, listener);
  } else {
    if (jsvIsArray(eventListeners)) {
      // we already have an array, just add to it
      jsvArrayPush(eventListeners, listener);
    } else {
      // not an array - we need to make it an array
      JsVar *arr = jsvNewWithFlags(JSV_ARRAY);
      jsvArrayPush(arr, eventListeners);
      jsvArrayPush(arr, listener);
      jsvSetValueOfName(eventList, arr);
      jsvUnLock(arr);
    }
  }
  jsvUnLock(eventListeners);
  jsvUnLock(eventList);
  /* Special case if we're a data listener and data has already arrived then
   * we queue an event immediately. */
  if (jsvIsStringEqual(event, "data")) {
    JsVar *buf = jsvObjectGetChild(parent, STREAM_BUFFER_NAME, 0);
    if (jsvIsString(buf)) {
      jsiQueueObjectCallbacks(parent, "#ondata", &buf, 1);
      jsvRemoveNamedChild(parent, STREAM_BUFFER_NAME);
    }
    jsvUnLock(buf);
  }
}
示例#14
0
void jsvIteratorNew(JsvIterator *it, JsVar *obj, JsvIteratorFlags flags) {
  if (jsvIsArray(obj) || jsvIsObject(obj) || jsvIsFunction(obj) || jsvIsGetterOrSetter(obj)) {
    it->type = JSVI_OBJECT;
    if (jsvIsArray(obj) && (flags&JSIF_EVERY_ARRAY_ELEMENT)) {
      it->type = JSVI_FULLARRAY;
      it->it.obj.index = 0;
      it->it.obj.var = jsvLockAgain(obj);
    }
    jsvObjectIteratorNew(&it->it.obj.it, obj);
  } else if (jsvIsArrayBuffer(obj)) {
    it->type = JSVI_ARRAYBUFFER;
    jsvArrayBufferIteratorNew(&it->it.buf, obj, 0);
  } else if (jsvHasCharacterData(obj)) {
    it->type = JSVI_STRING;
    jsvStringIteratorNew(&it->it.str, obj, 0);
  } else assert(0);
}
示例#15
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);

}
示例#16
0
static bool jsfGetJSONForObjectItWithCallback(JsvObjectIterator *it, JSONFlags flags, const char *whitespace, JSONFlags nflags, vcbprintf_callback user_callback, void *user_data, bool first) {
  bool needNewLine = false;
  size_t sinceNewLine = 0;
  while (jsvObjectIteratorHasValue(it) && !jspIsInterrupted()) {
    JsVar *index = jsvObjectIteratorGetKey(it);
    JsVar *item = jsvGetValueOfName(index);
    bool hidden = jsvIsInternalObjectKey(index) ||
        ((flags & JSON_IGNORE_FUNCTIONS) && jsvIsFunction(item)) ||
        ((flags&JSON_NO_UNDEFINED) && jsvIsUndefined(item)) ||
        jsvIsGetterOrSetter(item);
    if (!hidden) {
      sinceNewLine++;
      if (!first) cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?", ":",");
      bool newNeedsNewLine = (flags&JSON_SOME_NEWLINES) && jsonNeedsNewLine(item);
      if ((flags&JSON_SOME_NEWLINES) && sinceNewLine>JSON_ITEMS_ON_LINE_OBJECT)
        needNewLine = true;
      if (flags&JSON_ALL_NEWLINES) {
        needNewLine = true;
        newNeedsNewLine = true;
      }
      if (needNewLine || newNeedsNewLine) {
        jsonNewLine(nflags, whitespace, user_callback, user_data);
        needNewLine = false;
        sinceNewLine = 0;
      }
      bool addQuotes = true;
      if (flags&JSON_DROP_QUOTES) {
        if (jsvIsIntegerish(index)) addQuotes = false;
        else if (jsvIsString(index) && jsvGetStringLength(index)<15) {
          char buf[16];
          jsvGetString(index,buf,sizeof(buf));
          if (isIDString(buf)) addQuotes=false;
        }
      }
      cbprintf(user_callback, user_data, addQuotes?"%q%s":"%v%s", index, (flags&JSON_PRETTY)?": ":":");
      if (first)
        first = false;
      jsfGetJSONWithCallback(item, nflags, whitespace, user_callback, user_data);
      needNewLine = newNeedsNewLine;
    }
    jsvUnLock2(index, item);
    jsvObjectIteratorNext(it);
  }
  return needNewLine;
}
示例#17
0
/*JSON{
  "type" : "staticmethod",
  "class" : "net",
  "name" : "connect",
  "generate_full" : "jswrap_net_connect(options, callback, ST_NORMAL)",
  "params" : [
    ["options","JsVar","An object containing host,port fields"],
    ["callback","JsVar","A function(res) that will be called when a connection is made. You can then call `res.on('data', function(data) { ... })` and `res.on('close', function() { ... })` to deal with the response."]
  ],
  "return" : ["JsVar","Returns a new net.Socket object"],
  "return_object" : "Socket"
}
Create a socket connection
*/
JsVar *jswrap_net_connect(JsVar *options, JsVar *callback, SocketType socketType) {
  bool unlockOptions = false;
  if (jsvIsString(options)) {
    options = jswrap_url_parse(options, false);
    unlockOptions = true;
  }
  if (!jsvIsObject(options)) {
    jsError("Expecting Options to be an Object but it was %t", options);
    return 0;
  }
#ifdef USE_TLS
  if ((socketType&ST_TYPE_MASK) == ST_HTTP) {
    JsVar *protocol = jsvObjectGetChild(options, "protocol", 0);
    if (protocol && jsvIsStringEqual(protocol, "https:")) {
      socketType |= ST_TLS;
    }
    jsvUnLock(protocol);
  }
#endif

  // Make sure we have a function as callback, or nothing (which is OK too)
  JsVar *skippedCallback = jsvSkipName(callback);
  if (!jsvIsUndefined(skippedCallback)) {
    if (!jsvIsFunction(skippedCallback)) {
      jsError("Expecting Callback Function but got %t", skippedCallback);
      jsvUnLock(skippedCallback);
      return 0;
    }
    jsvUnLock(skippedCallback);
  } else {
    callback = NULL;
  }
  JsVar *rq = clientRequestNew(socketType, options, callback);
  if (unlockOptions) jsvUnLock(options);

  if ((socketType&ST_TYPE_MASK) != ST_HTTP) {
    JsNetwork net;
    if (networkGetFromVarIfOnline(&net)) {
      clientRequestConnect(&net, rq);
    }
    networkFree(&net);
  }

  return rq;
}
示例#18
0
JsVar *_jswrap_array_map_or_forEach(JsVar *parent, JsVar *funcVar, JsVar *thisVar, bool isMap) {
  if (!jsvIsFunction(funcVar)) {
    jsError("Array.map's first argument should be a function");
    return 0;
  }
  if (!jsvIsUndefined(thisVar) && !jsvIsObject(thisVar)) {
    jsError("Arraymap's second argument should be undefined, or an object");
    return 0;
  }
  JsVar *array = 0;
  if (isMap)
    array = jsvNewWithFlags(JSV_ARRAY);
  if (array || !isMap) {
   JsVarRef childRef = parent->firstChild;
   while (childRef) {
     JsVar *child = jsvLock(childRef);
     if (jsvIsInt(child)) {
       JsVar *args[3], *mapped;
       args[0] = jsvLock(child->firstChild);
       // child is a variable name, create a new variable for the index
       args[1] = jsvNewFromInteger(jsvGetInteger(child));
       args[2] = parent;
       mapped = jspeFunctionCall(funcVar, 0, thisVar, false, 3, args);
       jsvUnLock(args[0]);
       jsvUnLock(args[1]);
       if (mapped) {
         if (isMap) {
           JsVar *name = jsvCopyNameOnly(child, false/*linkChildren*/, true/*keepAsName*/);
           if (name) { // out of memory?
             name->firstChild = jsvGetRef(jsvRef(mapped));
             jsvAddName(array, name);
             jsvUnLock(name);
           }
         }
         jsvUnLock(mapped);
       }
     }
     childRef = child->nextSibling;
     jsvUnLock(child);
   }
  }
  return array;
}
示例#19
0
void _jswrap_promise_add(JsVar *parent, JsVar *callback, const char *name) {
  if (!jsvIsFunction(callback)) {
    jsExceptionHere(JSET_TYPEERROR, "Callback must be a function, got %t", callback);
    return;
  }
  JsVar *c = jsvObjectGetChild(parent, name, 0);
  if (!c) {
    jsvObjectSetChild(parent, name, callback);
  } else {
    if (jsvIsArray(c)) {
      jsvArrayPush(c, callback);
    } else {
      JsVar *fns[2] = {c,callback};
      JsVar *arr = jsvNewArray(fns, 2);
      jsvObjectSetChild(parent, name, arr);
      jsvUnLock(arr);
    }
    jsvUnLock(c);
  }
}
示例#20
0
/*JSON{
  "type" : "staticmethod",
  "class" : "http",
  "name" : "get",
  "generate" : "jswrap_http_get",
  "params" : [
    ["options","JsVar","An object containing host,port,path,method fields"],
    ["callback","JsVar","A function(res) that will be called when a connection is made. You can then call `res.on('data', function(data) { ... })` and `res.on('close', function() { ... })` to deal with the response."]
  ],
  "return" : ["JsVar","Returns a new httpCRq object"],
  "return_object" : "httpCRq"
}
Create an HTTP Request - convenience function for ```http.request()```. `options.method` is set to 'get', and end is called automatically. See [the Internet page](/Internet) for more usage examples.
*/
JsVar *jswrap_http_get(JsVar *options, JsVar *callback) {
  JsNetwork net;
  if (!networkGetFromVarIfOnline(&net)) return 0;

  if (jsvIsObject(options)) {
    // if options is a string - it will be parsed, and GET will be set automatically
    JsVar *method = jsvNewFromString("GET");
    jsvUnLock2(jsvAddNamedChild(options, method, "method"), method);
  }
  JsVar *skippedCallback = jsvSkipName(callback);
  if (!jsvIsUndefined(skippedCallback) && !jsvIsFunction(skippedCallback)) {
    jsError("Expecting Callback Function but got %t", skippedCallback);
    jsvUnLock(skippedCallback);
    return 0;
  }
  jsvUnLock(skippedCallback);
  JsVar *cliReq = jswrap_net_connect(options, callback, ST_HTTP);
  if (cliReq) clientRequestEnd(&net, cliReq);
  networkFree(&net);
  return cliReq;
}
示例#21
0
JsVar *jswrap_http_request(JsVar *options, JsVar *callback) {
  bool unlockOptions = false;
  if (jsvIsString(options)) {
    options = jswrap_url_parse(options, false);
    unlockOptions = true;
  }
  if (!jsvIsObject(options)) {
    jsError("Expecting Options to be an Object but it was %t", options);
    return 0;
  }
  JsVar *skippedCallback = jsvSkipName(callback);
  if (!jsvIsFunction(skippedCallback)) {
    jsError("Expecting Callback Function but got %t", skippedCallback);
    jsvUnLock(skippedCallback);
    return 0;
  }
  jsvUnLock(skippedCallback);
  JsVar *rq = httpClientRequestNew(options, callback);
  if (unlockOptions) jsvUnLock(options);
  return rq;
}
示例#22
0
/*JSON{ "type":"function", "name" : "setTimeout",
         "description" : ["Call the function specified ONCE after the timeout in milliseconds.",
                          "The function that is being called may also take an argument, which is an object containing a field called 'time' (the time in seconds at which the timer happened)",
                          "for example: ```setTimeout(function (e) { print(e.time); }, 1000);```",
                          "This can also be removed using clearTimeout",
                          "**Note:** If `setDeepSleep(true)` has been called and the interval is greater than 5 seconds, Espruino may execute the interval up to 1 second late. This is because Espruino can only wake from deep sleep every second - and waking early would cause Espruino to waste power while it waited for the correct time." ],
         "generate" : "jswrap_interface_setTimeout",
         "params" : [ [ "function", "JsVar", "A Function or String to be executed"],
                      [ "timeout", "float", "The time until the function will be executed" ] ],
         "return" : ["JsVar", "An ID that can be passed to clearTimeout"]
}*/
JsVar *_jswrap_interface_setTimeoutOrInterval(JsVar *func, JsVarFloat interval, bool isTimeout) {
  // NOTE: The 5 sec delay mentioned in the description is handled by jshSleep
  JsVar *itemIndex = 0;
  if (!jsvIsFunction(func) && !jsvIsString(func)) {
    jsError("Function or String not supplied!");
  } else {
    // Create a new timer
    JsVar *timerPtr = jsvNewWithFlags(JSV_OBJECT);
    if (interval<TIMER_MIN_INTERVAL) interval=TIMER_MIN_INTERVAL;
    JsVarInt intervalInt = jshGetTimeFromMilliseconds(interval);
    jsvUnLock(jsvObjectSetChild(timerPtr, "time", jsvNewFromInteger(jshGetSystemTime() + intervalInt)));
    jsvUnLock(jsvObjectSetChild(timerPtr, "interval", jsvNewFromInteger(intervalInt)));
    if (!isTimeout) jsvUnLock(jsvObjectSetChild(timerPtr, "recur", jsvNewFromBool(true)));
    jsvObjectSetChild(timerPtr, "callback", func); // intentionally no unlock

    // Add to array
    itemIndex = jsvNewFromInteger(jsiTimerAdd(timerPtr));
    jsvUnLock(timerPtr);
  }
  return itemIndex;
}
/*JSON{ "type":"function", "name" : "edit",
        "description" : ["Fill the console with the contents of the given function, so you can edit it.",
                         "NOTE: This is a convenience function - it will not edit 'inner functions'. For that, you must edit the 'outer function' and re-execute it."],
        "generate" : "jswrap_interface_edit",
        "params" : [ [ "funcName", "JsVarName", "The name of the function to edit (either a string or just the unquoted name)"] ]
}*/
void jswrap_interface_edit(JsVar *funcName) {
  if (jsvIsString(funcName)) {
    JsVar *func = 0;
    if (jsvIsName(funcName))
      func = jsvSkipName(funcName);
    else
      func = jsvSkipNameAndUnLock(jsvFindChildFromVar(jsiGetParser()->root, funcName, 0));
    if (jsvIsFunction(func)) {
      JsVar *scopeVar = jsvFindChildFromString(func, JSPARSE_FUNCTION_SCOPE_NAME, false);
      JsVarRef scope = jsvGetRef(scopeVar);
      jsvUnLock(scopeVar);
      JsVar *newLine = jsvNewFromEmptyString();
      if (newLine) { // could be out of memory
        jsvAppendStringVarComplete(newLine, funcName);
        if (scope) {
          // If we have a scope, it's an internal function so we will need to write different code
          jsvAppendString(newLine, ".replaceWith(");
        } else {
          jsvAppendString(newLine, " = ");
        }
        JsVar *funcData = jsvAsString(func, false);
        if (funcData)
          jsvAppendStringVarComplete(newLine, funcData);
        jsvUnLock(funcData);
        if (scope) {
          jsvAppendString(newLine, ");");
        } else {
          jsvAppendString(newLine, ";");
        }
        jsiReplaceInputLine(newLine);
        jsvUnLock(newLine);
      }
    } else {
      jsError("Edit should be called with the name of a function");
    }
    jsvUnLock(func);
  } else {
    jsError("Edit should be called with edit(funcName) or edit('funcName')");
  }
}
示例#24
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, ",");
      cbprintf(user_callback, user_data, "%v", child);
    } 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 {
        cbprintf(user_callback, user_data, "%v", codeVar);
      }
    } else cbprintf(user_callback, user_data, "{}");
  }
  jsvUnLock(codeVar);
}
示例#25
0
/*JSON{
    "type" : "staticmethod",
    "class" : "NRF",
    "name" : "setScan",
    "generate" : "jswrap_nrf_bluetooth_setScan",
    "params" : [
      ["callback","JsVar","The callback to call with information about received, or undefined to stop"]
    ]
}

Start/stop listening for BLE advertising packets within range.

```
// Start scanning
NRF.setScan(function(d) {
  console.log(JSON.stringify(d,null,2));
});
// prints {"rssi":-72, "addr":"##:##:##:##:##:##", "data":new ArrayBuffer([2,1,6,...])}

// Stop Scanning
NRF.setScan(false);
```
*/
void jswrap_nrf_bluetooth_setScan(JsVar *callback) {
  uint32_t              err_code;
  // set the callback event variable
  if (!jsvIsFunction(callback)) callback=0;
  jsvObjectSetChild(execInfo.root, BLE_SCAN_EVENT, callback);
  // either start or stop scanning
  if (callback) {
    ble_gap_scan_params_t     m_scan_param;
    // non-selective scan
    m_scan_param.active       = 0;            // Active scanning set.
    m_scan_param.selective    = 0;            // Selective scanning not set.
    m_scan_param.interval     = SCAN_INTERVAL;// Scan interval.
    m_scan_param.window       = SCAN_WINDOW;  // Scan window.
    m_scan_param.p_whitelist  = NULL;         // No whitelist provided.
    m_scan_param.timeout      = 0x0000;       // No timeout.

    err_code = sd_ble_gap_scan_start(&m_scan_param);
  } else {
    err_code = sd_ble_gap_scan_stop();
  }
  if (err_code)
    jsExceptionHere(JSET_ERROR, "Got BLE error code %d", err_code);
}
示例#26
0
/*JSON{
  "type" : "function",
  "name" : "setTimeout",
  "generate" : "jswrap_interface_setTimeout",
  "params" : [
    ["function","JsVar","A Function or String to be executed"],
    ["timeout","float","The time until the function will be executed"]
  ],
  "return" : ["JsVar","An ID that can be passed to clearTimeout"]
}
Call the function specified ONCE after the timeout in milliseconds.

The function that is being called may also take an argument, which is an object containing a field called 'time' (the time in seconds at which the timer happened)

for example: ```setTimeout(function (e) { print(e.time); }, 1000);```

This can also be removed using clearTimeout

**Note:** If `setDeepSleep(true)` has been called and the interval is greater than 5 seconds, Espruino may execute the interval up to 1 second late. This is because Espruino can only wake from deep sleep every second - and waking early would cause Espruino to waste power while it waited for the correct time.
*/
JsVar *_jswrap_interface_setTimeoutOrInterval(JsVar *func, JsVarFloat interval, bool isTimeout) {
  // NOTE: The 5 sec delay mentioned in the description is handled by jshSleep
  JsVar *itemIndex = 0;
  if (!jsvIsFunction(func) && !jsvIsString(func)) {
    jsExceptionHere(JSET_ERROR, "Function or String not supplied!");
  } else {
    // Create a new timer
    JsVar *timerPtr = jsvNewWithFlags(JSV_OBJECT);
    if (interval<TIMER_MIN_INTERVAL) interval=TIMER_MIN_INTERVAL;
    JsSysTime intervalInt = jshGetTimeFromMilliseconds(interval);
    //jsiConsolePrintf("interval = %f,intervalInt = %d,now = %d,timeInt = %d\n",interval,intervalInt,jshGetSystemTime(),(jshGetSystemTime() - jsiLastIdleTime) + intervalInt);
    jsvUnLock(jsvObjectSetChild(timerPtr, "time", jsvNewFromLongInteger((jshGetSystemTime() - jsiLastIdleTime) + intervalInt)));
    if (!isTimeout) {
      jsvUnLock(jsvObjectSetChild(timerPtr, "interval", jsvNewFromLongInteger(intervalInt)));
    }
    jsvObjectSetChild(timerPtr, "callback", func); // intentionally no unlock

    // Add to array
    itemIndex = jsvNewFromInteger(jsiTimerAdd(timerPtr));
    jsvUnLock(timerPtr);
  }
  return itemIndex;
}
/*JSON{ "type":"method", "class": "Object", "name" : "on",
         "description" : ["Register an event listener for this object, for instance ```http.on('data', function(d) {...})```. See Node.js's EventEmitter."],
         "generate" : "jswrap_object_on",
         "params" : [ [ "event", "JsVar", "The name of the event, for instance 'data'"],
                      [ "listener", "JsVar", "The listener to call when this event is received"] ]
}*/
void jswrap_object_on(JsVar *parent, JsVar *event, JsVar *listener) {
  if (!jsvIsObject(parent)) {
      jsWarn("Parent must be a proper object - not a String, Integer, etc.");
      return;
    }
  if (!jsvIsString(event)) {
      jsWarn("First argument to EventEmitter.on(..) must be a string");
      return;
    }
  if (!jsvIsFunction(listener) && !jsvIsString(listener)) {
    jsWarn("Second argument to EventEmitter.on(..) must be a function or a String (containing code)");
    return;
  }
  char eventName[16] = "#on";
  jsvGetString(event, &eventName[3], sizeof(eventName)-4);

  JsVar *eventList = jsvFindChildFromString(parent, eventName, true);
  JsVar *eventListeners = jsvSkipName(eventList);
  if (jsvIsUndefined(eventListeners)) {
    // just add
    jsvSetValueOfName(eventList, listener);
  } else {
    if (jsvIsArray(eventListeners)) {
      // we already have an array, just add to it
      jsvArrayPush(eventListeners, listener);
    } else {
      // not an array - we need to make it an array
      JsVar *arr = jsvNewWithFlags(JSV_ARRAY);
      jsvArrayPush(arr, eventListeners);
      jsvArrayPush(arr, listener);
      jsvSetValueOfName(eventList, arr);
      jsvUnLock(arr);
    }
  }
  jsvUnLock(eventListeners);
  jsvUnLock(eventList);
}
示例#28
0
/*JSON{
  "type" : "method",
  "class" : "Ethernet",
  "name" : "getIP",
  "generate" : "jswrap_ethernet_getIP",
  "params" : [
    ["options","JsVar","An optional `callback(err, ipinfo)` function to be called back with the IP information."]
  ],
  "return" : ["JsVar",""]
}
Get the current IP address, subnet, gateway and mac address.
*/
JsVar *jswrap_ethernet_getIP(JsVar *wlanObj, JsVar *callback) {
  NOT_USED(wlanObj);

  if (networkState != NETWORKSTATE_ONLINE) {
    jsExceptionHere(JSET_ERROR, "Not connected to the internet");
    return 0;
  }

  JsNetwork net;
  if (!networkGetFromVar(&net)) return 0;

  wiz_NetInfo gWIZNETINFO;
  ctlnetwork(CN_GET_NETINFO, (void*)&gWIZNETINFO);

  /* If byte 1 is 0 we don't have a valid address */
  JsVar *data = jsvNewObject();
  networkPutAddressAsString(data, "ip", &gWIZNETINFO.ip[0], 4, 10, '.');
  networkPutAddressAsString(data, "subnet", &gWIZNETINFO.sn[0], 4, 10, '.');
  networkPutAddressAsString(data, "gateway", &gWIZNETINFO.gw[0], 4, 10, '.');
  networkPutAddressAsString(data, "dns", &gWIZNETINFO.dns[0], 4, 10, '.');
  networkPutAddressAsString(data, "mac", &gWIZNETINFO.mac[0], 6, 16, ':');

  networkFree(&net);

  // Schedule callback if a function was provided
  if (jsvIsFunction(callback)) {
    JsVar *params[2];
    params[0] = jsvNewWithFlags(JSV_NULL);
    params[1] = data;
    jsiQueueEvents(NULL, callback, params, 2);
    jsvUnLock(params[0]);
  }


  return data;
}
示例#29
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;
}
示例#30
0
void jsfGetJSONWithCallback(JsVar *var, JSONFlags flags, const char *whitespace, vcbprintf_callback user_callback, void *user_data) {
  JSONFlags nflags = flags + JSON_INDENT; // if we add a newline, make sure we indent any subsequent JSON more
  if (!whitespace) whitespace="  ";

  if (jsvIsUndefined(var)) {
    cbprintf(user_callback, user_data, "undefined");
  } else {
    // Use IS_RECURSING  flag to stop recursion
    if (var->flags & JSV_IS_RECURSING) {
      cbprintf(user_callback, user_data, " ... ");
      return;
    }
    var->flags |= JSV_IS_RECURSING;

    if (jsvIsArray(var)) {
      JsVarInt length = jsvGetArrayLength(var);
      bool limited = (flags&JSON_LIMIT) && (length>(JsVarInt)JSON_LIMIT_AMOUNT);
      bool needNewLine = false;
      cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?"[ ":"[");
      JsVarInt lastIndex = -1;
      bool numeric = true;
      bool first = true;
      JsvObjectIterator it;
      jsvObjectIteratorNew(&it, var);
      while (lastIndex+1<length && numeric && !jspIsInterrupted()) {
        JsVar *key = jsvObjectIteratorGetKey(&it);
        if (!jsvObjectIteratorHasValue(&it) || jsvIsNumeric(key)) {
          JsVarInt index = jsvObjectIteratorHasValue(&it) ? jsvGetInteger(key) : length-1;
          JsVar *item = jsvObjectIteratorGetValue(&it);
          while (lastIndex < index) {
            lastIndex++;
            if (!limited || lastIndex<(JsVarInt)JSON_LIMITED_AMOUNT || lastIndex>=length-(JsVarInt)JSON_LIMITED_AMOUNT) {
              if (!first) cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?", ":",");
              first = false;
              if (limited && lastIndex==length-(JsVarInt)JSON_LIMITED_AMOUNT) cbprintf(user_callback, user_data, JSON_LIMIT_TEXT);
              bool newNeedsNewLine = ((flags&JSON_SOME_NEWLINES) && jsonNeedsNewLine(item));
              if (flags&JSON_ALL_NEWLINES) {
                needNewLine = true;
                newNeedsNewLine = true;
              }
              if (needNewLine || newNeedsNewLine) {
                jsonNewLine(nflags, whitespace, user_callback, user_data);
                needNewLine = false;
              }
              if (lastIndex == index)
                jsfGetJSONWithCallback(item, nflags, whitespace, user_callback, user_data);
              else
                cbprintf(user_callback, user_data, (flags&JSON_NO_UNDEFINED)?"null":"undefined");
              needNewLine = newNeedsNewLine;
            }
          }
          jsvUnLock(item);
          jsvObjectIteratorNext(&it);
        } else {
          numeric = false;
        }
        jsvUnLock(key);
      }

      // non-numeric  - but NOT for standard JSON
      if ((flags&JSON_PRETTY))
        jsfGetJSONForObjectItWithCallback(&it, flags, whitespace, nflags, user_callback, user_data, first);
      jsvObjectIteratorFree(&it);
      if (needNewLine) jsonNewLine(flags, whitespace, user_callback, user_data);
      cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?" ]":"]");
    } else if (jsvIsArrayBuffer(var)) {
      JsvArrayBufferIterator it;
      bool allZero = true;
      jsvArrayBufferIteratorNew(&it, var, 0);
      while (jsvArrayBufferIteratorHasElement(&it)) {
        if (jsvArrayBufferIteratorGetFloatValue(&it)!=0)
          allZero = false;
        jsvArrayBufferIteratorNext(&it);
      }
      jsvArrayBufferIteratorFree(&it);
      bool asArray = flags&JSON_ARRAYBUFFER_AS_ARRAY;

      if (allZero && !asArray) {
        cbprintf(user_callback, user_data, "new %s(%d)", jswGetBasicObjectName(var), jsvGetArrayBufferLength(var));
      } else {
        const char *aname = jswGetBasicObjectName(var);
        /* You can't do `new ArrayBuffer([1,2,3])` so we have to output
         * `new Uint8Array([1,2,3]).buffer`! */
        bool isBasicArrayBuffer = strcmp(aname,"ArrayBuffer")==0;
        if (isBasicArrayBuffer) {
          aname="Uint8Array";
        }
        cbprintf(user_callback, user_data, asArray?"[":"new %s([", aname);
        if (flags&JSON_ALL_NEWLINES) jsonNewLine(nflags, whitespace, user_callback, user_data);
        size_t length = jsvGetArrayBufferLength(var);
        bool limited = (flags&JSON_LIMIT) && (length>JSON_LIMIT_AMOUNT);
        // no newlines needed for array buffers as they only contain simple stuff

        jsvArrayBufferIteratorNew(&it, var, 0);
        while (jsvArrayBufferIteratorHasElement(&it) && !jspIsInterrupted()) {
          if (!limited || it.index<JSON_LIMITED_AMOUNT || it.index>=length-JSON_LIMITED_AMOUNT) {
            if (it.index>0) cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?", ":",");
            if (flags&JSON_ALL_NEWLINES) jsonNewLine(nflags, whitespace, user_callback, user_data);
            if (limited && it.index==length-JSON_LIMITED_AMOUNT) cbprintf(user_callback, user_data, JSON_LIMIT_TEXT);
            JsVar *item = jsvArrayBufferIteratorGetValue(&it);
            jsfGetJSONWithCallback(item, nflags, whitespace, user_callback, user_data);
            jsvUnLock(item);
          }
          jsvArrayBufferIteratorNext(&it);
        }
        if (flags&JSON_ALL_NEWLINES) jsonNewLine(flags, whitespace, user_callback, user_data);
        jsvArrayBufferIteratorFree(&it);
        cbprintf(user_callback, user_data, asArray?"]":"])");
        if (isBasicArrayBuffer && !asArray) cbprintf(user_callback, user_data, ".buffer");
      }
    } else if (jsvIsObject(var)) {
      IOEventFlags device = (flags & JSON_SHOW_DEVICES) ? jsiGetDeviceFromClass(var) : EV_NONE;
      if (device!=EV_NONE) {
        cbprintf(user_callback, user_data, "%s", jshGetDeviceString(device));
      } else {
        bool showContents = true;
        if (flags & JSON_SHOW_OBJECT_NAMES) {
          JsVar *proto = jsvObjectGetChild(var, JSPARSE_INHERITS_VAR, 0);
          if (jsvHasChildren(proto)) {
            JsVar *constr = jsvObjectGetChild(proto, JSPARSE_CONSTRUCTOR_VAR, 0);
            if (constr) {
              JsVar *p = jsvGetIndexOf(execInfo.root, constr, true);
              if (p) cbprintf(user_callback, user_data, "%v: ", p);
              jsvUnLock2(p,constr);
              /* We had the constructor - now if there was a non-default toString function
               * we'll execute it and print the result */
              JsVar *toStringFn = jspGetNamedField(var, "toString", false);
              if (toStringFn && toStringFn->varData.native.ptr != (void (*)(void))jswrap_object_toString) {
                // Function found and it's not the default one - execute it
                JsVar *result = jspExecuteFunction(toStringFn,var,0,0);
                cbprintf(user_callback, user_data, "%v", result);
                jsvUnLock(result);
                showContents = false; // we already printed something
              }
              jsvUnLock(toStringFn);
            }
          }
          jsvUnLock(proto);
        }
        if (showContents) {
          JsvObjectIterator it;
          jsvObjectIteratorNew(&it, var);
          cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?"{ ":"{");
          bool needNewLine = jsfGetJSONForObjectItWithCallback(&it, flags, whitespace, nflags, user_callback, user_data, true);
          jsvObjectIteratorFree(&it);
          if (needNewLine) jsonNewLine(flags, whitespace, user_callback, user_data);
          cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?" }":"}");
        }
      }
    } else if (jsvIsFunction(var)) {
      if (flags & JSON_IGNORE_FUNCTIONS) {
        cbprintf(user_callback, user_data, "undefined");
      } else {
        cbprintf(user_callback, user_data, "function ");
        jsfGetJSONForFunctionWithCallback(var, nflags, user_callback, user_data);
      }
    } else if (jsvIsString(var) && !jsvIsName(var)) {
      if ((flags&JSON_LIMIT) && jsvGetStringLength(var)>JSON_LIMIT_STRING_AMOUNT) {
        // if the string is too big, split it and put dots in the middle
        JsVar *var1 = jsvNewFromStringVar(var, 0, JSON_LIMITED_STRING_AMOUNT);
        JsVar *var2 = jsvNewFromStringVar(var, jsvGetStringLength(var)-JSON_LIMITED_STRING_AMOUNT, JSON_LIMITED_STRING_AMOUNT);
        cbprintf(user_callback, user_data, "%q%s%q", var1, JSON_LIMIT_TEXT, var2);
        jsvUnLock2(var1, var2);
      } else {
        cbprintf(user_callback, user_data, "%q", var);
      }
    } else {
      cbprintf(user_callback, user_data, "%v", var);
    }

    var->flags &= ~JSV_IS_RECURSING;
  }
}