コード例 #1
0
ファイル: jswrap_array.c プロジェクト: ARMinARM/Espruino
/*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;
}
コード例 #2
0
ファイル: jswrap_object.c プロジェクト: david1983/Espruino
/*JSON{
  "type" : "method",
  "class" : "Function",
  "name" : "apply",
  "generate" : "jswrap_function_apply_or_call",
  "params" : [
    ["this","JsVar","The value to use as the 'this' argument when executing the function"],
    ["args","JsVar","Optional Array of Arguments"]
  ],
  "return" : ["JsVar","The return value of executing this function"]
}
This executes the function with the supplied 'this' argument and parameters
 */
JsVar *jswrap_function_apply_or_call(JsVar *parent, JsVar *thisArg, JsVar *argsArray) {
  unsigned int i;
  JsVar **args = 0;
  unsigned int argC = 0;

  if (jsvIsIterable(argsArray)) {
    argC = (unsigned int)jsvGetLength(argsArray);
    if (argC>64) {
      jsExceptionHere(JSET_ERROR, "Array passed to Function.apply is too big! Maximum 64 arguments, got %d", argC);
      return 0;
    }
    args = (JsVar**)alloca((size_t)argC * sizeof(JsVar*));
    for (i=0;i<argC;i++) args[i] = 0;
    // TODO: Use jsvGetArrayItems?
    JsvIterator it;
    jsvIteratorNew(&it, argsArray);
    while (jsvIteratorHasElement(&it)) {
      JsVarInt idx = jsvGetIntegerAndUnLock(jsvIteratorGetKey(&it));
      if (idx>=0 && idx<(int)argC) {
        assert(!args[idx]); // just in case there were dups
        args[idx] = jsvIteratorGetValue(&it);
      }
      jsvIteratorNext(&it);
    }
    jsvIteratorFree(&it);
  } else if (!jsvIsUndefined(argsArray)) {
    jsExceptionHere(JSET_ERROR, "Second argument to Function.apply must be iterable, got %t", argsArray);
    return 0;
  }

  JsVar *r = jspeFunctionCall(parent, 0, thisArg, false, (int)argC, args);
  jsvUnLockMany(argC, args);
  return r;
}
コード例 #3
0
/*JSON{
  "type" : "method",
  "class" : "ArrayBufferView",
  "name" : "set",
  "generate" : "jswrap_arraybufferview_set",
  "params" : [
    ["arr","JsVar","Floating point index to access"],
    ["offset","int32","The offset in this array at which to write the values (optional)"]
  ]
}
Copy the contents of `array` into this one, mapping `this[x+offset]=array[x];`
*/
void jswrap_arraybufferview_set(JsVar *parent, JsVar *arr, int offset) {
  if (!(jsvIsString(arr) || jsvIsArray(arr) || jsvIsArrayBuffer(arr))) {
    jsExceptionHere(JSET_ERROR, "Expecting first argument to be an array, not %t", arr);
    return;
  }
  JsvIterator itsrc;
  jsvIteratorNew(&itsrc, arr);
  JsvArrayBufferIterator itdst;
  jsvArrayBufferIteratorNew(&itdst, parent, (size_t)offset);

  bool useInts = !JSV_ARRAYBUFFER_IS_FLOAT(itdst.type) || jsvIsString(arr);

  while (jsvIteratorHasElement(&itsrc) && jsvArrayBufferIteratorHasElement(&itdst)) {
    if (useInts) {
      jsvArrayBufferIteratorSetIntegerValue(&itdst, jsvIteratorGetIntegerValue(&itsrc));
    } else {
      JsVar *value = jsvIteratorGetValue(&itsrc);
      jsvArrayBufferIteratorSetValue(&itdst, value);
      jsvUnLock(value);
    }
    jsvArrayBufferIteratorNext(&itdst);
    jsvIteratorNext(&itsrc);
  }
  jsvArrayBufferIteratorFree(&itdst);
  jsvIteratorFree(&itsrc);
}
コード例 #4
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;
}
コード例 #5
0
ファイル: jswrap_arraybuffer.c プロジェクト: CWBudde/Espruino
JsVar *jswrap_typedarray_constructor(JsVarDataArrayBufferViewType type, JsVar *arr, JsVarInt byteOffset, JsVarInt length) {
  JsVar *arrayBuffer = 0;
  // Only allow use of byteOffset/length if we're passing an ArrayBuffer - NOT A VIEW.
  bool copyData = false;
  if (jsvIsArrayBuffer(arr) && arr->varData.arraybuffer.type==ARRAYBUFFERVIEW_ARRAYBUFFER) {
    arrayBuffer = jsvLockAgain(arr);
  } else if (jsvIsNumeric(arr)) {
    length = jsvGetInteger(arr);
    byteOffset = 0;
    arrayBuffer = jswrap_arraybuffer_constructor((int)JSV_ARRAYBUFFER_GET_SIZE(type)*length);
  } else if (jsvIsArray(arr) || jsvIsArrayBuffer(arr)) {
    length = (JsVarInt)jsvGetLength(arr);
    byteOffset = 0;
    arrayBuffer = jswrap_arraybuffer_constructor((int)JSV_ARRAYBUFFER_GET_SIZE(type)*length);
    copyData = true; // so later on we'll populate this
  }
  if (!arrayBuffer) {
    jsExceptionHere(JSET_ERROR, "Unsupported first argument of type %t\n", arr);
    return 0;
  }
  if (length==0) {
    length = ((JsVarInt)jsvGetArrayBufferLength(arrayBuffer)-byteOffset) / (JsVarInt)JSV_ARRAYBUFFER_GET_SIZE(type); 
    if (length<0) length=0;
  }
  JsVar *typedArr = jsvNewWithFlags(JSV_ARRAYBUFFER);
  if (typedArr) {
    typedArr->varData.arraybuffer.type = type;
    typedArr->varData.arraybuffer.byteOffset = (unsigned short)byteOffset;
    typedArr->varData.arraybuffer.length = (unsigned short)length;
    jsvSetFirstChild(typedArr, jsvGetRef(jsvRef(arrayBuffer)));

    if (copyData) {
      // if we were given an array, populate this ArrayBuffer
      JsvIterator it;
      jsvIteratorNew(&it, arr, JSIF_DEFINED_ARRAY_ElEMENTS);
      while (jsvIteratorHasElement(&it)) {
        JsVar *idx = jsvIteratorGetKey(&it);
        if (jsvIsInt(idx)) {
          JsVar *val = jsvIteratorGetValue(&it);
          // TODO: This is horrible! We need to try and iterate properly...
          jsvArrayBufferSet(typedArr, (size_t)jsvGetInteger(idx), val);
          jsvUnLock(val);
        }
        jsvUnLock(idx);
        jsvIteratorNext(&it);
      }
      jsvIteratorFree(&it);
    }
  }
  jsvUnLock(arrayBuffer);
  return typedArr;
}
コード例 #6
0
ファイル: jswrap_array.c プロジェクト: cephdon/Espruino
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
/** Iterate over the contents of var, calling callback for each. Contents may be:
 *   * numeric -> output
 *   * a string -> output each character
 *   * array/arraybuffer -> call itself on each element
 *   * object -> call itself object.count times, on object.data
 */
bool jsvIterateCallback(JsVar *data, void (*callback)(int item, void *callbackData), void *callbackData) {
  bool ok = true;
  if (jsvIsNumeric(data)) {
    callback((int)jsvGetInteger(data), callbackData);
  } else if (jsvIsObject(data)) {
    JsVar *countVar = jsvObjectGetChild(data, "count", 0);
    JsVar *dataVar = jsvObjectGetChild(data, "data", 0);
    if (countVar && dataVar && jsvIsNumeric(countVar)) {
      int n = (int)jsvGetInteger(countVar);
      while (ok && n-- > 0) {
        ok = jsvIterateCallback(dataVar, callback, callbackData);
      }
    } else {
      jsWarn("If specifying an object, it must be of the form {data : ..., count : N}");
    }
    jsvUnLock(countVar);
    jsvUnLock(dataVar);
  } else if (jsvIsString(data)) {
    JsvStringIterator it;
    jsvStringIteratorNew(&it, data, 0);
    while (jsvStringIteratorHasChar(&it) && ok) {
      char ch = jsvStringIteratorGetChar(&it);
      callback(ch, callbackData);
      jsvStringIteratorNext(&it);
    }
    jsvStringIteratorFree(&it);
  } else if (jsvIsIterable(data)) {
    JsvIterator it;
    jsvIteratorNew(&it, data);
    while (jsvIteratorHasElement(&it) && ok) {
      JsVar *el = jsvIteratorGetValue(&it);
      ok = jsvIterateCallback(el, callback, callbackData);
      jsvUnLock(el);
      jsvIteratorNext(&it);
    }
    jsvIteratorFree(&it);
  } else {
    jsWarn("Expecting a number or something iterable, got %t", data);
    ok = false;
  }
  return ok;
}
コード例 #8
0
ファイル: jsvariterator.c プロジェクト: programmicha/Espruino
/**
 * \brief Iterate over the contents of the content of a variable, calling callback for each.
 * Contents may be:
 * * numeric -> output
 * * a string -> output each character
 * * array/arraybuffer -> call itself on each element
 * object -> call itself object.count times, on object.data
 */
bool jsvIterateCallback(
    JsVar *data,                                    // The data to iterate over.
	void (*callback)(int item, void *callbackData), // The callback function invoke.
	void *callbackData                              // Data to be passed to the callback function
  ) {
  bool ok = true;
  // Handle the data being a single numeric.
  if (jsvIsNumeric(data)) {
    callback((int)jsvGetInteger(data), callbackData);
  }
  // Handle the data being an object.
  else if (jsvIsObject(data)) {
    JsVar *countVar = jsvObjectGetChild(data, "count", 0);
    JsVar *dataVar = jsvObjectGetChild(data, "data", 0);
    if (countVar && dataVar && jsvIsNumeric(countVar)) {
      int n = (int)jsvGetInteger(countVar);
      while (ok && n-- > 0) {
        ok = jsvIterateCallback(dataVar, callback, callbackData);
      }
    } else {
      jsWarn("If specifying an object, it must be of the form {data : ..., count : N}");
    }
    jsvUnLock2(countVar, dataVar);
  }
  // Handle the data being a string
  else if (jsvIsString(data)) {
    JsvStringIterator it;
    jsvStringIteratorNew(&it, data, 0);
    while (jsvStringIteratorHasChar(&it) && ok) {
      char ch = jsvStringIteratorGetChar(&it);
      callback(ch, callbackData);
      jsvStringIteratorNext(&it);
    }
    jsvStringIteratorFree(&it);
  }
  // Handle the data being an array buffer
  else if (jsvIsArrayBuffer(data)) {
    JsvArrayBufferIterator it;
    jsvArrayBufferIteratorNew(&it, data, 0);
    if (JSV_ARRAYBUFFER_GET_SIZE(it.type) == 1 && !JSV_ARRAYBUFFER_IS_SIGNED(it.type)) {
      // faster for single byte arrays.
      while (jsvArrayBufferIteratorHasElement(&it)) {
        callback((int)(unsigned char)jsvStringIteratorGetChar(&it.it), callbackData);
        jsvArrayBufferIteratorNext(&it);
      }
    } else {
      while (jsvArrayBufferIteratorHasElement(&it)) {
        callback((int)jsvArrayBufferIteratorGetIntegerValue(&it), callbackData);
        jsvArrayBufferIteratorNext(&it);
      }
    }
    jsvArrayBufferIteratorFree(&it);
  }
  // Handle the data being iterable
  else if (jsvIsIterable(data)) {
    JsvIterator it;
    jsvIteratorNew(&it, data);
    while (jsvIteratorHasElement(&it) && ok) {
      JsVar *el = jsvIteratorGetValue(&it);
      ok = jsvIterateCallback(el, callback, callbackData);
      jsvUnLock(el);
      jsvIteratorNext(&it);
    }
    jsvIteratorFree(&it);
  } else {
    jsWarn("Expecting a number or something iterable, got %t", data);
    ok = false;
  }
  return ok;
}
コード例 #9
0
ファイル: jswrap_array.c プロジェクト: etx/Espruino
JsVar *_jswrap_array_iterate_with_callback(const char *name, JsVar *parent, JsVar *funcVar, JsVar *thisVar, bool wantArray, bool isBoolCallback, bool expectedValue) {
  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;
  }
  if (!jsvIsUndefined(thisVar) && !jsvIsObject(thisVar)) {
    jsExceptionHere(JSET_ERROR, "Array.%s's second argument should be undefined, or an object", name);
    return 0;
  }
  JsVar *result = 0;
  if (wantArray)
    result = jsvNewEmptyArray();
  bool isDone = false;
  if (result || !wantArray) {
    JsvIterator it;
    jsvIteratorNew(&it, parent);
    while (jsvIteratorHasElement(&it) && !isDone) {
      JsVar *index = jsvIteratorGetKey(&it);
      if (jsvIsInt(index)) {
        JsVarInt idxValue = jsvGetInteger(index);

        JsVar *args[3], *cb_result;
        args[0] = jsvIteratorGetValue(&it);
        args[1] = jsvNewFromInteger(idxValue); // child is a variable name, create a new variable for the index
        args[2] = parent;
        cb_result = jspeFunctionCall(funcVar, 0, thisVar, false, 3, args);
        jsvUnLockMany(2,args);
        if (cb_result) {
          bool matched;
          if (isBoolCallback)
            matched = (jsvGetBool(cb_result) == expectedValue);
          if (wantArray) {
            if (isBoolCallback) { // filter
              if (matched) {
                jsvArrayPushAndUnLock(result, jsvIteratorGetValue(&it));
              }
            } else { // map
              JsVar *name = jsvNewFromInteger(idxValue);
              if (name) { // out of memory?
                jsvMakeIntoVariableName(name, cb_result);
                jsvAddName(result, name);
                jsvUnLock(name);
              }
            }
          } else {
            // break the loop early if expecting a particular value and didn't get it
            if (isBoolCallback && !matched)
              isDone = true;
          }
          jsvUnLock(cb_result);
        }
      }
      jsvUnLock(index);
      jsvIteratorNext(&it);
    }
    jsvIteratorFree(&it);
  }
  /* boolean result depends on whether the loop terminated
     early for 'some' or completed for 'every' */
  if (!wantArray && isBoolCallback) {
    result = jsvNewFromBool(isDone != expectedValue);
  }
  return result;
}
コード例 #10
0
ファイル: jsvariterator.c プロジェクト: MaBecker/Espruino
/**
 Iterate over the contents of the content of a variable, calling callback for each.
 Contents may be:
 * numeric -> output
 * a string -> output each character
 * array/arraybuffer -> call itself on each element
 * {data:..., count:...} -> call itself object.count times, on object.data
 * {callback:...} -> call the given function, call itself on return value
 */
bool jsvIterateCallback(
    JsVar *data,
    jsvIterateCallbackFn callback,
    void *callbackData
  ) {
  bool ok = true;
  // Handle the data being a single numeric.
  if (jsvIsNumeric(data)) {
    callback((int)jsvGetInteger(data), callbackData);
  }
  // Handle the data being an object.
  else if (jsvIsObject(data)) {
    JsVar *callbackVar = jsvObjectGetChild(data, "callback", 0);
    if (jsvIsFunction(callbackVar)) {
      JsVar *result = jspExecuteFunction(callbackVar,0,0,NULL);
      jsvUnLock(callbackVar);
      if (result) {
        bool r = jsvIterateCallback(result, callback, callbackData);
        jsvUnLock(result);
        return r;
      }
      return true;
    }
    jsvUnLock(callbackVar);
    JsVar *countVar = jsvObjectGetChild(data, "count", 0);
    JsVar *dataVar = jsvObjectGetChild(data, "data", 0);
    if (countVar && dataVar && jsvIsNumeric(countVar)) {
      int n = (int)jsvGetInteger(countVar);
      while (ok && n-- > 0) {
        ok = jsvIterateCallback(dataVar, callback, callbackData);
      }
    } else {
      jsExceptionHere(JSET_TYPEERROR, "If specifying an object, it must be of the form {data : ..., count : N} or {callback : fn} - got %j", data);
      ok = false;
    }
    jsvUnLock2(countVar, dataVar);
  }
  // Handle the data being a string
  else if (jsvIsString(data)) {
    JsvStringIterator it;
    jsvStringIteratorNew(&it, data, 0);
    while (jsvStringIteratorHasChar(&it) && ok) {
      char ch = jsvStringIteratorGetChar(&it);
      callback(ch, callbackData);
      jsvStringIteratorNext(&it);
    }
    jsvStringIteratorFree(&it);
  }
  // Handle the data being an array buffer
  else if (jsvIsArrayBuffer(data)) {
    JsvArrayBufferIterator it;
    jsvArrayBufferIteratorNew(&it, data, 0);
    if (JSV_ARRAYBUFFER_GET_SIZE(it.type) == 1 && !JSV_ARRAYBUFFER_IS_SIGNED(it.type)) {
      JsvStringIterator *sit = &it.it;
      // faster for single byte arrays - read using the string iterator.
      while (jsvStringIteratorHasChar(sit)) {
        callback((int)(unsigned char)jsvStringIteratorGetChar(sit), callbackData);
        jsvStringIteratorNextInline(sit);
      }
    } else {
      while (jsvArrayBufferIteratorHasElement(&it)) {
        callback((int)jsvArrayBufferIteratorGetIntegerValue(&it), callbackData);
        jsvArrayBufferIteratorNext(&it);
      }
    }
    jsvArrayBufferIteratorFree(&it);
  }
  // Handle the data being iterable
  else if (jsvIsIterable(data)) {
    JsvIterator it;
    jsvIteratorNew(&it, data, JSIF_EVERY_ARRAY_ELEMENT);
    while (jsvIteratorHasElement(&it) && ok) {
      JsVar *el = jsvIteratorGetValue(&it);
      ok = jsvIterateCallback(el, callback, callbackData);
      jsvUnLock(el);
      jsvIteratorNext(&it);
    }
    jsvIteratorFree(&it);
  } else {
    jsExceptionHere(JSET_TYPEERROR, "Expecting a number or something iterable, got %t", data);
    ok = false;
  }
  return ok;
}