Пример #1
0
/*JSON{
  "type" : "staticmethod",
  "class" : "console",
  "name" : "log",
  "generate" : "jswrap_interface_print",
  "params" : [
    ["text","JsVarArray","One or more arguments to print"]
  ]
}
Print the supplied string(s) to the console

 **Note:** If you're connected to a computer (not a wall adaptor) via USB but **you are not running a terminal app** then when you print data Espruino may pause execution and wait until the computer requests the data it is trying to print.
 */
void jswrap_interface_print(JsVar *v) {
  assert(jsvIsArray(v));

  jsiConsoleRemoveInputLine();
  JsvObjectIterator it;
  jsvObjectIteratorNew(&it, v);
  while (jsvObjectIteratorHasValue(&it)) {
    JsVar *v = jsvObjectIteratorGetValue(&it);
    if (jsvIsString(v))
      jsiConsolePrintStringVar(v);
    else
      jsfPrintJSON(v, JSON_PRETTY | JSON_NEWLINES);
    jsvUnLock(v);
    jsvObjectIteratorNext(&it);
    if (jsvObjectIteratorHasValue(&it))
      jsiConsolePrint(" ");
  }
  jsvObjectIteratorFree(&it);
  jsiConsolePrint("\n");
}
Пример #2
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);
  }
}
Пример #3
0
/*JSON{ "type":"method", "class": "Function", "name" : "apply",
         "description" : ["This executes the function with the supplied 'this' argument and parameters"],
         "generate" : "jswrap_function_apply",
         "params" : [ [ "this", "JsVar", "The value to use as the 'this' argument when executing the function"],
                      [ "args", "JsVar", "Optional Array of Aruments"]
                    ],
         "return" : [ "JsVar", "The return value of executing this function" ]
}*/
JsVar *jswrap_function_apply(JsVar *parent, JsVar *thisArg, JsVar *argsArray) {
  unsigned int i;
  JsVar **args = 0;
  size_t argC = 0;

  if (jsvIsArray(argsArray)) {
    argC = (unsigned int)jsvGetArrayLength(argsArray);
    if (argC>64) argC=64; // sanity
#ifdef RT_USING_JS
    args = (JsVar**)rt_malloc((size_t)argC * sizeof(JsVar*));
#else
    args = (JsVar**)alloca((size_t)argC * sizeof(JsVar*));
#endif

    for (i=0;i<argC;i++) args[i] = 0;
    JsArrayIterator it;
    jsvArrayIteratorNew(&it, argsArray);
    while (jsvArrayIteratorHasElement(&it)) {
      JsVarInt idx = jsvGetIntegerAndUnLock(jsvArrayIteratorGetIndex(&it));
      if (idx>=0 && idx<argC) {
        assert(!args[idx]); // just in case there were dups
        args[idx] = jsvArrayIteratorGetElement(&it);
      }
      jsvArrayIteratorNext(&it);
    }
    jsvArrayIteratorFree(&it);
  } else if (!jsvIsUndefined(argsArray)) {
    jsWarn("Second argument to Function.apply must be an array");
  }

  JsVar *r = jspeFunctionCall(parent, 0, thisArg, false, (int)argC, args);
  for (i=0;i<argC;i++) jsvUnLock(args[i]);
#ifdef RT_USING_JS
  rt_free(args);
#else
#error "please define RT_USING_JS on rtconfig.h"
#endif
  return r;
}
Пример #4
0
/*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);
}
Пример #5
0
/** This is for Object.keys and Object. However it uses a callback so doesn't allocate anything */
void jswrap_object_keys_or_property_names_cb(
    JsVar *obj,
    bool includeNonEnumerable,  ///< include 'hidden' items
    bool includePrototype, ///< include items for the prototype too (for autocomplete)
    void (*callback)(void *data, JsVar *name),
    void *data
) {
  // strings are iterable, but we shouldn't try and show keys for them
  if (jsvIsIterable(obj)) {
    JsvIsInternalChecker checkerFunction = jsvGetInternalFunctionCheckerFor(obj);

    JsvIterator it;
    jsvIteratorNew(&it, obj);
    while (jsvIteratorHasElement(&it)) {
      JsVar *key = jsvIteratorGetKey(&it);
      if (!(checkerFunction && checkerFunction(key)) || (jsvIsStringEqual(key, JSPARSE_CONSTRUCTOR_VAR))) {
        /* Not sure why constructor is included in getOwnPropertyNames, but
         * not in for (i in ...) but it is, so we must explicitly override the
         * check in jsvIsInternalObjectKey! */
        JsVar *name = jsvAsArrayIndexAndUnLock(jsvCopyNameOnly(key, false, false));
        if (name) {
          callback(data, name);
          jsvUnLock(name);
        }
      }
      jsvUnLock(key);
      jsvIteratorNext(&it);
    }
    jsvIteratorFree(&it);
  }

  /* Search our built-in symbol table
     Assume that ALL builtins are non-enumerable. This isn't great but
     seems to work quite well right now! */
  if (includeNonEnumerable) {
    const JswSymList *symbols = 0;

    JsVar *protoOwner = jspGetPrototypeOwner(obj);
    if (protoOwner) {
      // If protoOwner then this is the prototype (protoOwner is the object)
      symbols = jswGetSymbolListForObjectProto(protoOwner);
      jsvUnLock(protoOwner);
    } else if (!jsvIsObject(obj) || jsvIsRoot(obj)) {
      // get symbols, but only if we're not doing it on a basic object
      symbols = jswGetSymbolListForObject(obj);
    }

    while (symbols) {
      unsigned int i;
      unsigned char symbolCount = READ_FLASH_UINT8(&symbols->symbolCount);
      for (i=0;i<symbolCount;i++) {
        unsigned short strOffset = READ_FLASH_UINT16(&symbols->symbols[i].strOffset);
#ifndef USE_FLASH_MEMORY
        JsVar *name = jsvNewFromString(&symbols->symbolChars[strOffset]);
#else
        // On the esp8266 the string is in flash, so we have to copy it to RAM first
        // We can't use flash_strncpy here because it assumes that strings start on a word
        // boundary and that's not the case here.
        char buf[64], *b = buf, c; const char *s = &symbols->symbolChars[strOffset];
        do { c = READ_FLASH_UINT8(s++); *b++ = c; } while (c && b != buf+64);
        JsVar *name = jsvNewFromString(buf);
#endif
        //os_printf_plus("OBJ cb %s\n", buf);
        callback(data, name);
        jsvUnLock(name);
      }

      symbols = 0;
      if (includePrototype) {
        includePrototype = false;
        symbols = jswGetSymbolListForObjectProto(obj);
      }
    }

    if (jsvIsArray(obj) || jsvIsString(obj)) {
      JsVar *name = jsvNewFromString("length");
      callback(data, name);
      jsvUnLock(name);
    }
  }
}
Пример #6
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;
  }
}
Пример #7
0
void jsfGetJSONWithCallback(JsVar *var, JSONFlags flags, 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 (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)) {
      size_t length = (size_t)jsvGetArrayLength(var);
      bool limited = (flags&JSON_LIMIT) && (length>JSON_LIMIT_AMOUNT);
      bool needNewLine = false;
      size_t i;
      cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?"[ ":"[");
      for (i=0;i<length && !jspIsInterrupted();i++) {
        if (!limited || i<JSON_LIMITED_AMOUNT || i>=length-JSON_LIMITED_AMOUNT) {
          if (i>0) cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?", ":",");
          if (limited && i==length-JSON_LIMITED_AMOUNT) {
            if (needNewLine) jsonNewLine(nflags, user_callback, user_data);
            cbprintf(user_callback, user_data, JSON_LIMIT_TEXT);
          }
          JsVar *item = jsvGetArrayItem(var, (JsVarInt)i);
          if (jsvIsUndefined(item) && (flags&JSON_NO_UNDEFINED))
              item = jsvNewWithFlags(JSV_NULL);
          bool newNeedsNewLine = (flags&JSON_NEWLINES) && jsonNeedsNewLine(item);
          if (needNewLine || newNeedsNewLine) {
            jsonNewLine(nflags, user_callback, user_data);
            needNewLine = false;
          }
          jsfGetJSONWithCallback(item, nflags, user_callback, user_data);
          needNewLine = newNeedsNewLine;
          jsvUnLock(item);
        }
      }
      if (needNewLine) jsonNewLine(flags, 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);

      if (allZero) {
        cbprintf(user_callback, user_data, "new %s(%d)", jswGetBasicObjectName(var), jsvGetArrayBufferLength(var));
      } else {
        cbprintf(user_callback, user_data, "new %s([", jswGetBasicObjectName(var));
        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 (limited && it.index==length-JSON_LIMITED_AMOUNT) cbprintf(user_callback, user_data, JSON_LIMIT_TEXT);
            JsVar *item = jsvArrayBufferIteratorGetValue(&it);
            jsfGetJSONWithCallback(item, nflags, user_callback, user_data);
            jsvUnLock(item);
          }
          jsvArrayBufferIteratorNext(&it);
        }
        jsvArrayBufferIteratorFree(&it);
        cbprintf(user_callback, user_data, "])");
      }
    } 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 first = true;
        bool needNewLine = false;
        size_t sinceNewLine = 0;
        JsvObjectIterator it;
        jsvObjectIteratorNew(&it, var);
        cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?"{ ":"{");
        while (jsvObjectIteratorHasValue(&it) && !jspIsInterrupted()) {
          JsVar *index = jsvObjectIteratorGetKey(&it);
          JsVar *item = jsvObjectIteratorGetValue(&it);
          bool hidden = jsvIsInternalObjectKey(index) ||
                        ((flags & JSON_IGNORE_FUNCTIONS) && jsvIsFunction(item)) ||
                        ((flags&JSON_NO_UNDEFINED) && jsvIsUndefined(item));
          if (!hidden) {
            sinceNewLine++;
            if (!first) cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?", ":",");
            bool newNeedsNewLine = (flags&JSON_NEWLINES) && jsonNeedsNewLine(item);
            if ((flags&JSON_NEWLINES) && sinceNewLine>JSON_ITEMS_ON_LINE_OBJECT)
              needNewLine = true;
            if (needNewLine || newNeedsNewLine) {
              jsonNewLine(nflags, user_callback, user_data);
              needNewLine = false;
              sinceNewLine = 0;
            }
            cbprintf(user_callback, user_data, (flags&JSON_PRETTY)?"%q: ":"%q:", index);
            if (first)
              first = false;
            jsfGetJSONWithCallback(item, nflags, user_callback, user_data);
            needNewLine = newNeedsNewLine;
          }
          jsvUnLock(index);
          jsvUnLock(item);
          jsvObjectIteratorNext(&it);
        }
        jsvObjectIteratorFree(&it);
        if (needNewLine) jsonNewLine(flags, 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);
        jsvUnLock(var1);
        jsvUnLock(var2);
      } else {
        cbprintf(user_callback, user_data, "%q", var);
      }
    } else {
      cbprintf(user_callback, user_data, "%v", var);
    }

    var->flags &= ~JSV_IS_RECURSING;
  }
}
Пример #8
0
/*JSON{
  "type" : "method",
  "class" : "Array",
  "name" : "splice",
  "generate" : "jswrap_array_splice",
  "params" : [
    ["index","int","Index at which to start changing the array. If negative, will begin that many elements from the end"],
    ["howMany","JsVar","An integer indicating the number of old array elements to remove. If howMany is 0, no elements are removed."],
    ["elements","JsVarArray","One or more items to add to the array"]
  ],
  "return" : ["JsVar","An array containing the removed elements. If only one element is removed, an array of one element is returned."]
}
Both remove and add items to an array
 */
JsVar *jswrap_array_splice(JsVar *parent, JsVarInt index, JsVar *howManyVar, JsVar *elements) {
  if (!jsvIsArray(parent)) return 0;
  JsVarInt len = jsvGetArrayLength(parent);
  if (index<0) index+=len;
  if (index<0) index=0;
  if (index>len) index=len;
  JsVarInt howMany = len; // how many to delete!
  if (jsvIsInt(howManyVar)) howMany = jsvGetInteger(howManyVar);
  if (howMany > len-index) howMany = len-index;
  JsVarInt newItems = jsvGetArrayLength(elements);
  JsVarInt shift = newItems-howMany;

  bool needToAdd = false;
  JsVar *result = jsvNewEmptyArray();

  JsvObjectIterator it;
  jsvObjectIteratorNew(&it, parent);
  while (jsvObjectIteratorHasValue(&it) && !needToAdd) {
    bool goToNext = true;
    JsVar *idxVar = jsvObjectIteratorGetKey(&it);
    if (idxVar && jsvIsInt(idxVar)) {
      JsVarInt idx = jsvGetInteger(idxVar);
      if (idx<index) {
        // do nothing...
      } else if (idx<index+howMany) { // must delete
        if (result) { // append to result array
          JsVar *el = jsvObjectIteratorGetValue(&it);
          jsvArrayPushAndUnLock(result, el);
        }
        // delete
        goToNext = false;
        JsVar *toRemove = jsvObjectIteratorGetKey(&it);
        jsvObjectIteratorNext(&it);
        jsvRemoveChild(parent, toRemove);
        jsvUnLock(toRemove);
      } else { // we're greater than the amount we need to remove now
        needToAdd = true;
        goToNext = false;
      }
    }
    jsvUnLock(idxVar);
    if (goToNext) jsvObjectIteratorNext(&it);
  }
  // now we add everything
  JsVar *beforeIndex = jsvObjectIteratorGetKey(&it);
  JsvObjectIterator itElement;
  jsvObjectIteratorNew(&itElement, elements);
  while (jsvObjectIteratorHasValue(&itElement)) {
    JsVar *element = jsvObjectIteratorGetValue(&itElement);
    jsvArrayInsertBefore(parent, beforeIndex, element);
    jsvUnLock(element);
    jsvObjectIteratorNext(&itElement);
  }
  jsvObjectIteratorFree(&itElement);
  jsvUnLock(beforeIndex);
  // And finally renumber
  while (jsvObjectIteratorHasValue(&it)) {
    JsVar *idxVar = jsvObjectIteratorGetKey(&it);
    if (idxVar && jsvIsInt(idxVar)) {
      jsvSetInteger(idxVar, jsvGetInteger(idxVar)+shift);
    }
    jsvUnLock(idxVar);
    jsvObjectIteratorNext(&it);
  }
  // free
  jsvObjectIteratorFree(&it);

  // and reset array size
  jsvSetArrayLength(parent, len + shift, false);

  return result;
}
Пример #9
0
/** This is for Object.keys and Object. However it uses a callback so doesn't allocate anything */
void jswrap_object_keys_or_property_names_cb(
    JsVar *obj,
    bool includeNonEnumerable,  ///< include 'hidden' items
    bool includePrototype, ///< include items for the prototype too (for autocomplete)
    void (*callback)(void *data, JsVar *name),
    void *data
) {
  // strings are iterable, but we shouldn't try and show keys for them
  if (jsvIsIterable(obj)) {
    JsvIsInternalChecker checkerFunction = jsvGetInternalFunctionCheckerFor(obj);

    JsvIterator it;
    jsvIteratorNew(&it, obj);
    while (jsvIteratorHasElement(&it)) {
      JsVar *key = jsvIteratorGetKey(&it);
      if (!(checkerFunction && checkerFunction(key)) || (jsvIsStringEqual(key, JSPARSE_CONSTRUCTOR_VAR))) {
        /* Not sure why constructor is included in getOwnPropertyNames, but
         * not in for (i in ...) but it is, so we must explicitly override the
         * check in jsvIsInternalObjectKey! */
        JsVar *name = jsvAsArrayIndexAndUnLock(jsvCopyNameOnly(key, false, false));
        if (name) {
          callback(data, name);
          jsvUnLock(name);
        }
      }
      jsvUnLock(key);
      jsvIteratorNext(&it);
    }
    jsvIteratorFree(&it);
  }

  /* Search our built-in symbol table
     Assume that ALL builtins are non-enumerable. This isn't great but
     seems to work quite well right now! */
  if (includeNonEnumerable) {
    JsVar *protoOwner = jspGetPrototypeOwner(obj);
    if (protoOwner) {
      // If protoOwner then this is the prototype (protoOwner is the object)
      const JswSymList *symbols = jswGetSymbolListForObjectProto(protoOwner);
      jsvUnLock(protoOwner);
      _jswrap_object_keys_or_property_names_iterator(symbols, callback, data);
    } else if (!jsvIsObject(obj) || jsvIsRoot(obj)) {
      // get symbols, but only if we're not doing it on a basic object
       const JswSymList *symbols = jswGetSymbolListForObject(obj);
      _jswrap_object_keys_or_property_names_iterator(symbols, callback, data);
    }

    if (includePrototype) {
      if (jsvIsObject(obj)) {
        JsVar *proto = jsvObjectGetChild(obj, JSPARSE_INHERITS_VAR, 0);
        while (jsvIsObject(proto)) {
          const JswSymList *symbols = jswGetSymbolListForObjectProto(proto);
          _jswrap_object_keys_or_property_names_iterator(symbols, callback, data);
          JsVar *p2 = jsvObjectGetChild(proto, JSPARSE_INHERITS_VAR, 0);
          jsvUnLock(proto);
          proto = p2;
        }
      }
      // finally include Object/String/etc
      const JswSymList *symbols = jswGetSymbolListForObjectProto(obj);
      _jswrap_object_keys_or_property_names_iterator(symbols, callback, data);
    }

    if (jsvIsArray(obj) || jsvIsString(obj)) {
      JsVar *name = jsvNewFromString("length");
      callback(data, name);
      jsvUnLock(name);
    }
  }
}
Пример #10
0
void jsvObjectIteratorNew(JsvObjectIterator *it, JsVar *obj) {
  assert(jsvIsArray(obj) || jsvIsObject(obj) || jsvIsFunction(obj) || jsvIsGetterOrSetter(obj));
  it->var = jsvLockSafe(jsvGetFirstChild(obj));
}
Пример #11
0
/** This is for Object.keys and Object. */
JsVar *jswrap_object_keys_or_property_names(
    JsVar *obj,
    bool includeNonEnumerable,  ///< include 'hidden' items
    bool includePrototype) { ///< include items for the prototype too (for autocomplete)

  JsVar *arr = jsvNewWithFlags(JSV_ARRAY);
  if (!arr) return 0;

  // strings are iterable, but we shouldn't try and show keys for them
  if (jsvIsIterable(obj)) {
    JsvIsInternalChecker checkerFunction = jsvGetInternalFunctionCheckerFor(obj);

    JsvIterator it;
    jsvIteratorNew(&it, obj);
    while (jsvIteratorHasElement(&it)) {
      JsVar *key = jsvIteratorGetKey(&it);
      if (!(checkerFunction && checkerFunction(key)) || (jsvIsStringEqual(key, JSPARSE_CONSTRUCTOR_VAR))) {
        /* Not sure why constructor is included in getOwnPropertyNames, but
         * not in for (i in ...) but it is, so we must explicitly override the
         * check in jsvIsInternalObjectKey! */
        JsVar *name = jsvAsArrayIndexAndUnLock(jsvCopyNameOnly(key, false, false));
        if (name) {
          jsvArrayPushAndUnLock(arr, name);
        }
      }
      jsvUnLock(key);
      jsvIteratorNext(&it);
    }
    jsvIteratorFree(&it);
  }

  /* Search our built-in symbol table
     Assume that ALL builtins are non-enumerable. This isn't great but
     seems to work quite well right now! */
  if (includeNonEnumerable) {
    const JswSymList *symbols = 0;

    JsVar *protoOwner = jspGetPrototypeOwner(obj);
    if (protoOwner) {
      // If protoOwner then this is the prototype (protoOwner is the object)
      symbols = jswGetSymbolListForObjectProto(protoOwner);
      jsvUnLock(protoOwner);
    } else if (!jsvIsObject(obj) || jsvIsRoot(obj)) {
      // get symbols, but only if we're not doing it on a basic object
      symbols = jswGetSymbolListForObject(obj);
    }

    if (symbols) {
      unsigned int i;
      for (i=0;i<symbols->symbolCount;i++)
        jsvArrayAddString(arr, &symbols->symbolChars[symbols->symbols[i].strOffset]);
    }

    if (includePrototype) {
      symbols = jswGetSymbolListForObjectProto(obj);
      if (symbols) {
        unsigned int i;
        for (i=0;i<symbols->symbolCount;i++)
          jsvArrayAddString(arr, &symbols->symbolChars[symbols->symbols[i].strOffset]);
      }
    }

    if (jsvIsArray(obj) || jsvIsString(obj)) {
      jsvArrayAddString(arr, "length");
    }
  }

  return arr;
}