/*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; size_t argC = 0; if (jsvIsArray(argsArray)) { argC = (size_t)jsvGetArrayLength(argsArray); if (argC>64) argC=64; // sanity args = (JsVar**)alloca((size_t)argC * sizeof(JsVar*)); for (i=0;i<argC;i++) args[i] = 0; JsvObjectIterator it; jsvObjectIteratorNew(&it, argsArray); while (jsvObjectIteratorHasValue(&it)) { JsVarInt idx = jsvGetIntegerAndUnLock(jsvObjectIteratorGetKey(&it)); if (idx>=0 && idx<(int)argC) { assert(!args[idx]); // just in case there were dups args[idx] = jsvObjectIteratorGetValue(&it); } jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&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]); return r; }
JsVar *jswrap_arguments() { JsVar *scope = 0; if (execInfo.scopeCount>0) scope = jsvLock(execInfo.scopes[execInfo.scopeCount-1]); if (!jsvIsFunction(scope)) { jsvUnLock(scope); jsError("Can only use 'arguments' variable inside a function"); return 0; } JsVar *args = jsvNewWithFlags(JSV_ARRAY); if (!args) return 0; // out of memory JsvObjectIterator it; jsvObjectIteratorNew(&it, scope); while (jsvObjectIteratorHasElement(&it)) { JsVar *idx = jsvObjectIteratorGetKey(&it); if (jsvIsFunctionParameter(idx)) { JsVar *val = jsvSkipOneName(idx); jsvArrayPushAndUnLock(args, val); } jsvUnLock(idx); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); jsvUnLock(scope); return args; }
/*JSON{ "type" : "staticmethod", "class" : "NRF", "name" : "setAdvertising", "generate" : "jswrap_nrf_bluetooth_setAdvertising", "params" : [ ["data","JsVar","The data to advertise as an object - see below for more info"] ] } Data is of the form `{ UUID : data_as_byte_array }`. For example to return battery level at 95%, do: ``` NRF.setAdvertising({ 0x180F : [95] }); ``` Or you could report the current temperature: ``` setInterval(function() { NRF.setAdvertising({ 0x1809 : [0|E.getTemperature()] }); }, 30000); ``` */ void jswrap_nrf_bluetooth_setAdvertising(JsVar *data) { uint32_t err_code; ble_advdata_t advdata; setup_advdata(&advdata); if (jsvIsObject(data)) { ble_advdata_service_data_t *service_data = (ble_advdata_service_data_t*)alloca(jsvGetChildren(data)*sizeof(ble_advdata_service_data_t)); int n = 0; JsvObjectIterator it; jsvObjectIteratorNew(&it, data); while (jsvObjectIteratorHasValue(&it)) { service_data[n].service_uuid = jsvGetIntegerAndUnLock(jsvObjectIteratorGetKey(&it)); JsVar *v = jsvObjectIteratorGetValue(&it); JSV_GET_AS_CHAR_ARRAY(dPtr, dLen, v); jsvUnLock(v); service_data[n].data.size = dLen; service_data[n].data.p_data = dPtr; jsvObjectIteratorNext(&it); n++; } jsvObjectIteratorFree(&it); advdata.service_data_count = n; advdata.p_service_data_array = service_data; } else if (!jsvIsUndefined(data)) { jsExceptionHere(JSET_TYPEERROR, "Expecting object or undefined, got %t", data); } err_code = ble_advdata_set(&advdata, NULL); if (err_code) jsExceptionHere(JSET_ERROR, "Got BLE error code %d", err_code); }
/*JSON{ "type" : "function", "name" : "clearTimeout", "generate" : "jswrap_interface_clearTimeout", "params" : [ ["id","JsVar","The id returned by a previous call to setTimeout"] ] } Clear the Timeout that was created with setTimeout, for example: ```var id = setTimeout(function () { print('foo'); }, 1000);``` ```clearTimeout(id);``` If no argument is supplied, all timers and intervals are stopped */ void _jswrap_interface_clearTimeoutOrInterval(JsVar *idVar, bool isTimeout) { JsVar *timerArrayPtr = jsvLock(timerArray); if (jsvIsUndefined(idVar)) { /* Delete all timers EXCEPT those with a 'watch' field, as those were generated by jsinteractive.c for debouncing watches */ JsvObjectIterator it; jsvObjectIteratorNew(&it, timerArrayPtr); while (jsvObjectIteratorHasValue(&it)) { JsVar *timerPtr = jsvObjectIteratorGetValue(&it); JsVar *watchPtr = jsvObjectGetChild(timerPtr, "watch", 0); if (!watchPtr) jsvObjectIteratorRemoveAndGotoNext(&it, timerArrayPtr); else jsvObjectIteratorNext(&it); jsvUnLock2(watchPtr, timerPtr); } jsvObjectIteratorFree(&it); } else { JsVar *child = jsvIsBasic(idVar) ? jsvFindChildFromVar(timerArrayPtr, idVar, false) : 0; if (child) { JsVar *timerArrayPtr = jsvLock(timerArray); jsvRemoveChild(timerArrayPtr, child); jsvUnLock2(child, timerArrayPtr); } else { if (isTimeout) jsExceptionHere(JSET_ERROR, "Unknown Timeout"); else jsExceptionHere(JSET_ERROR, "Unknown Interval"); } } jsvUnLock(timerArrayPtr); jsiTimersChanged(); // mark timers as changed }
/*JSON{ "type" : "kill", "generate" : "jswrap_file_kill" }*/ void jswrap_file_kill() { JsVar *arr = fsGetArray(false); if (arr) { JsvObjectIterator it; jsvObjectIteratorNew(&it, arr); while (jsvObjectIteratorHasValue(&it)) { JsVar *file = jsvObjectIteratorGetValue(&it); jswrap_file_close(file); jsvUnLock(file); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); jsvRemoveAllChildren(arr); jsvUnLock(arr); } // close fs library #ifndef LINUX if (fat_initialised) { fat_initialised = false; f_mount(0, 0, 0); } #endif #ifdef SD_CARD_ANYWHERE sdSPISetup(0, PIN_UNDEFINED); #endif }
/*JSON{ "type" : "staticmethod", "class" : "Promise", "name" : "all", "generate" : "jswrap_promise_all", "params" : [ ["promises","JsVar","An array of promises"] ], "return" : ["JsVar","A new Promise"] } Return a new promise that is resolved when all promises in the supplied array are resolved. */ JsVar *jswrap_promise_all(JsVar *arr) { if (!jsvIsIterable(arr)) { jsExceptionHere(JSET_TYPEERROR, "Expecting something iterable, got %t", arr); return 0; } JsVar *promise = jspNewObject(0, "Promise"); if (!promise) return 0; JsVar *resolve = jsvNewNativeFunction((void (*)(void))jswrap_promise_all_resolve, JSWAT_VOID|JSWAT_THIS_ARG|(JSWAT_JSVAR<<JSWAT_BITS)); JsVar *reject = jsvNewNativeFunction((void (*)(void))jswrap_promise_all_reject, JSWAT_VOID|JSWAT_THIS_ARG|(JSWAT_JSVAR<<JSWAT_BITS)); if (resolve && reject) { jsvObjectSetChild(resolve, JSPARSE_FUNCTION_THIS_NAME, promise); jsvObjectSetChild(reject, JSPARSE_FUNCTION_THIS_NAME, promise); int promises = 0; JsvObjectIterator it; jsvObjectIteratorNew(&it, arr); while (jsvObjectIteratorHasValue(&it)) { JsVar *p = jsvObjectIteratorGetValue(&it); jsvUnLock(jswrap_promise_then(p, resolve)); jsvUnLock(jswrap_promise_catch(p, reject)); jsvUnLock(p); promises++; jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); jsvObjectSetChildAndUnLock(promise, JS_PROMISE_COUNT_NAME, jsvNewFromInteger(promises)); jsvObjectSetChildAndUnLock(promise, JS_PROMISE_RESULT_NAME, jsvNewEmptyArray()); } jsvUnLock2(resolve, reject); return promise; }
/*JSON{ "type" : "method", "class" : "Object", "name" : "removeAllListeners", "generate" : "jswrap_object_removeAllListeners", "params" : [ ["event","JsVar","The name of the event, for instance 'data'"] ] } Removes all listeners, or those of the specified event. */ void jswrap_object_removeAllListeners(JsVar *parent, JsVar *event) { if (!jsvHasChildren(parent)) { jsWarn("Parent must be an object - not a String, Integer, etc."); return; } if (jsvIsString(event)) { // remove the whole child containing listeners JsVar *eventName = jsvVarPrintf(JS_EVENT_PREFIX"%s",event); if (!eventName) return; // no memory JsVar *eventList = jsvFindChildFromVar(parent, eventName, true); jsvUnLock(eventName); if (eventList) { jsvRemoveChild(parent, eventList); jsvUnLock(eventList); } } else if (jsvIsUndefined(event)) { // Eep. We must remove everything beginning with '#on' (JS_EVENT_PREFIX) JsvObjectIterator it; jsvObjectIteratorNew(&it, parent); while (jsvObjectIteratorHasValue(&it)) { JsVar *key = jsvObjectIteratorGetKey(&it); jsvObjectIteratorNext(&it); if (jsvIsStringEqualOrStartsWith(key, JS_EVENT_PREFIX, true)) { // begins with #on - we must kill it jsvRemoveChild(parent, key); } jsvUnLock(key); } jsvObjectIteratorFree(&it); } else { jsWarn("First argument to EventEmitter.removeAllListeners(..) must be a string, or undefined"); return; } }
/*JSON{ "type":"method", "class": "Function", "name" : "replaceWith", "description" : ["This replaces the function with the one in the argument - while keeping the old function's scope. This allows inner functions to be edited, and is used when edit() is called on an inner function."], "generate" : "jswrap_function_replaceWith", "params" : [ [ "newFunc", "JsVar", "The new function to replace this function with"] ] }*/ void jswrap_function_replaceWith(JsVar *oldFunc, JsVar *newFunc) { if (!jsvIsFunction(newFunc)) { jsWarn("First argument of replaceWith should be a function - ignoring"); return; } // Grab scope - the one thing we want to keep JsVar *scope = jsvFindChildFromString(oldFunc, JSPARSE_FUNCTION_SCOPE_NAME, false); // so now remove all existing entries jsvRemoveAllChildren(oldFunc); // now re-add scope jsvAddName(oldFunc, scope); jsvUnLock(scope); // now re-add other entries JsObjectIterator it; jsvObjectIteratorNew(&it, newFunc); while (jsvObjectIteratorHasElement(&it)) { JsVar *el = jsvObjectIteratorGetKey(&it); jsvObjectIteratorNext(&it); if (!jsvIsStringEqual(el, JSPARSE_FUNCTION_SCOPE_NAME)) { JsVar *copy = jsvCopy(el); if (copy) { jsvAddName(oldFunc, copy); jsvUnLock(copy); } } } jsvObjectIteratorFree(&it); }
/*JSON{ "type" : "method", "class" : "Object", "name" : "emit", "generate" : "jswrap_object_emit", "params" : [ ["event","JsVar","The name of the event, for instance 'data'"], ["args","JsVarArray","Optional arguments"] ] } Call the event listeners for this object, for instance ```http.emit('data', 'Foo')```. See Node.js's EventEmitter. */ void jswrap_object_emit(JsVar *parent, JsVar *event, JsVar *argArray) { if (!jsvIsObject(parent)) { jsWarn("Parent must be a proper object - not a String, Integer, etc."); return; } if (!jsvIsString(event)) { jsWarn("First argument to EventEmitter.emit(..) must be a string"); return; } char eventName[16] = "#on"; jsvGetString(event, &eventName[3], sizeof(eventName)-4); // extract data const int MAX_ARGS = 4; JsVar *args[MAX_ARGS]; int n = 0; JsvObjectIterator it; jsvObjectIteratorNew(&it, argArray); while (jsvObjectIteratorHasValue(&it)) { if (n>=MAX_ARGS) { jsWarn("Too many arguments"); break; } args[n++] = jsvObjectIteratorGetValue(&it); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); jsiQueueObjectCallbacks(parent, eventName, args, n); // unlock while (n--) jsvUnLock(args[n]); }
/*JSON{ "type" : "method", "class" : "Object", "name" : "emit", "generate" : "jswrap_object_emit", "params" : [ ["event","JsVar","The name of the event, for instance 'data'"], ["args","JsVarArray","Optional arguments"] ] } Call the event listeners for this object, for instance ```http.emit('data', 'Foo')```. See Node.js's EventEmitter. */ void jswrap_object_emit(JsVar *parent, JsVar *event, JsVar *argArray) { if (!jsvHasChildren(parent)) { jsWarn("Parent must be an object - not a String, Integer, etc."); return; } if (!jsvIsString(event)) { jsWarn("First argument to EventEmitter.emit(..) must be a string"); return; } char eventName[16]; if (!jswrap_object_get_event_name(eventName, event)) return; // extract data const unsigned int MAX_ARGS = 4; JsVar *args[MAX_ARGS]; unsigned int n = 0; JsvObjectIterator it; jsvObjectIteratorNew(&it, argArray); while (jsvObjectIteratorHasValue(&it)) { if (n>=MAX_ARGS) { jsWarn("Too many arguments"); break; } args[n++] = jsvObjectIteratorGetValue(&it); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); jsiQueueObjectCallbacks(parent, eventName, args, (int)n); // unlock jsvUnLockMany(n, args); }
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); }
/*JSON{ "type" : "idle", "generate" : "jswrap_waveform_idle", "ifndef" : "SAVE_ON_FLASH" }*/ bool jswrap_waveform_idle() { JsVar *waveforms = jsvObjectGetChild(execInfo.hiddenRoot, JSI_WAVEFORM_NAME, 0); if (waveforms) { JsvObjectIterator it; jsvObjectIteratorNew(&it, waveforms); while (jsvObjectIteratorHasValue(&it)) { JsVar *waveform = jsvObjectIteratorGetValue(&it); bool running = jsvGetBoolAndUnLock(jsvObjectGetChild(waveform, "running", 0)); if (running) { JsVar *buffer = jswrap_waveform_getBuffer(waveform,0,0); UtilTimerTask task; // Search for a timer task if (!jstGetLastBufferTimerTask(buffer, &task)) { // if the timer task is now gone... JsVar *arrayBuffer = jsvObjectGetChild(waveform, "buffer", 0); jsiQueueObjectCallbacks(waveform, "#onfinish", &arrayBuffer, 1); jsvUnLock(arrayBuffer); running = false; jsvObjectSetChildAndUnLock(waveform, "running", jsvNewFromBool(running)); } else { // If the timer task is still there... if (task.data.buffer.nextBuffer && task.data.buffer.nextBuffer != task.data.buffer.currentBuffer) { // if it is a double-buffered task int currentBuffer = (jsvGetRef(buffer)==task.data.buffer.currentBuffer) ? 0 : 1; int oldBuffer = jsvGetIntegerAndUnLock(jsvObjectGetChild(waveform, "currentBuffer", JSV_INTEGER)); if (oldBuffer != currentBuffer) { // buffers have changed - fire off a 'buffer' event with the buffer that needs to be filled jsvObjectSetChildAndUnLock(waveform, "currentBuffer", jsvNewFromInteger(currentBuffer)); JsVar *arrayBuffer = jsvObjectGetChild(waveform, (currentBuffer==0) ? "buffer" : "buffer2", 0); jsiQueueObjectCallbacks(waveform, "#onbuffer", &arrayBuffer, 1); jsvUnLock(arrayBuffer); } } } jsvUnLock(buffer); } jsvUnLock(waveform); // if not running, remove waveform from this list if (!running) jsvObjectIteratorRemoveAndGotoNext(&it, waveforms); else jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); jsvUnLock(waveforms); } return false; // no need to stay awake - an IRQ will wake us }
NO_INLINE static void _socketCloseAllConnectionsFor(JsNetwork *net, char *name) { JsVar *arr = socketGetArray(name, false); if (!arr) return; JsvObjectIterator it; jsvObjectIteratorNew(&it, arr); while (jsvObjectIteratorHasValue(&it)) { JsVar *connection = jsvObjectIteratorGetValue(&it); _socketConnectionKill(net, connection); jsvUnLock(connection); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); jsvRemoveAllChildren(arr); jsvUnLock(arr); }
/*JSON{ "type" : "staticmethod", "class" : "Math", "name" : "max", "generate_full" : "jswrap_math_minmax(args, true)", "params" : [ ["args","JsVarArray","A floating point value to clip"] ], "return" : ["float","The maximum of the supplied values"] } Find the maximum of a series of numbers */ JsVarFloat jswrap_math_minmax(JsVar *args, bool isMax) { JsVarFloat v = isMax ? -INFINITY : INFINITY; JsvObjectIterator it; jsvObjectIteratorNew(&it, args); while (jsvObjectIteratorHasValue(&it)) { JsVarFloat arg = jsvGetFloatAndUnLock(jsvObjectIteratorGetValue(&it)); if ((isMax && arg > v) || (!isMax && arg < v) || isnan(arg)) v = arg; jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); return v; }
/*JSON{ "type" : "method", "class" : "Array", "name" : "push", "generate" : "jswrap_array_push", "params" : [ ["arguments","JsVarArray","One or more arguments to add"] ], "return" : ["int","The new size of the array"] } Push a new value onto the end of this array' This is the opposite of `[1,2,3].unshift(0)`, which adds one or more elements to the beginning of the array. */ JsVarInt jswrap_array_push(JsVar *parent, JsVar *args) { if (!jsvIsArray(parent)) return -1; JsVarInt len = -1; JsvObjectIterator it; jsvObjectIteratorNew(&it, args); while (jsvObjectIteratorHasValue(&it)) { JsVar *el = jsvObjectIteratorGetValue(&it); len = jsvArrayPush(parent, el); jsvUnLock(el); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); if (len<0) len = jsvGetArrayLength(parent); return len; }
/*JSON{ "type" : "idle", "generate" : "jswrap_pipe_idle", "ifndef" : "SAVE_ON_FLASH" }*/ bool jswrap_pipe_idle() { bool wasBusy = false; JsVar *arr = pipeGetArray(false); if (arr) { JsvObjectIterator it; jsvObjectIteratorNew(&it, arr); while (jsvObjectIteratorHasValue(&it)) { JsVar *pipe = jsvObjectIteratorGetValue(&it); wasBusy |= handlePipe(arr, &it, pipe); jsvUnLock(pipe); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); jsvUnLock(arr); } return wasBusy; }
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); }
/*JSON{ "type" : "staticmethod", "class" : "String", "name" : "fromCharCode", "generate" : "jswrap_string_fromCharCode", "params" : [ ["code","JsVarArray","One or more character codes to create a string from (range 0-255)."] ], "return" : ["JsVar","The character"] } Return the character(s) represented by the given character code(s). */ JsVar *jswrap_string_fromCharCode(JsVar *arr) { assert(jsvIsArray(arr)); JsVar *r = jsvNewFromEmptyString(); if (!r) return 0; JsvObjectIterator it; jsvObjectIteratorNew(&it, arr); while (jsvObjectIteratorHasValue(&it)) { char ch = (char)jsvGetIntegerAndUnLock(jsvObjectIteratorGetValue(&it)); jsvAppendStringBuf(r, &ch, 1); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); return r; }
/*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); }
bool bleRemoveChild(JsVar *parent, JsVar *blevar){ bool ret = false; JsvObjectIterator it; jsvObjectIteratorNew(&it, parent); while (jsvObjectIteratorHasValue(&it)) { JsVar *child = jsvObjectIteratorGetKey(&it); JsVar *name = jsvNewFromStringVar(child, 0, 10); if(jsvIsEqual(name,blevar)){ jsvRemoveChild(parent,child); ret = true; } jsvUnLock(child); jsvUnLock(name); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); return ret; }
static void httpAppendHeaders(JsVar *string, JsVar *headerObject) { // append headers JsvObjectIterator it; jsvObjectIteratorNew(&it, headerObject); while (jsvObjectIteratorHasValue(&it)) { JsVar *k = jsvAsString(jsvObjectIteratorGetKey(&it), true); JsVar *v = jsvAsString(jsvObjectIteratorGetValue(&it), true); jsvAppendStringVarComplete(string, k); jsvAppendString(string, ": "); jsvAppendStringVarComplete(string, v); jsvAppendString(string, "\r\n"); jsvUnLock2(k, v); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); // free headers }
/*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"); }
/*JSON{ "type":"staticmethod", "class" : "Modules", "name" : "getCached", "description" : "Return an array of module names that have been cached", "generate" : "jswrap_modules_getCached", "return" : ["JsVar", "An array of module names"] }*/ JsVar *jswrap_modules_getCached() { JsVar *arr = jsvNewWithFlags(JSV_ARRAY); if (!arr) return 0; // out of memory JsVar *moduleList = jswrap_modules_getModuleList(); if (!moduleList) return arr; // out of memory JsvObjectIterator it; jsvObjectIteratorNew(&it, moduleList); while (jsvObjectIteratorHasValue(&it)) { JsVar *idx = jsvObjectIteratorGetKey(&it); JsVar *idxCopy = jsvCopyNameOnly(idx, false, false); jsvArrayPushAndUnLock(arr, idxCopy); jsvUnLock(idx); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); jsvUnLock(moduleList); return arr; }
/*JSON{ "type" : "staticmethod", "class" : "Object", "name" : "defineProperties", "generate" : "jswrap_object_defineProperties", "params" : [ ["obj","JsVar","An object"], ["props","JsVar","An object whose fields represent property names, and whose values are property descriptors."] ], "return" : ["JsVar","The object, obj."] } Adds new properties to the Object. See `Object.defineProperty` for more information */ JsVar *jswrap_object_defineProperties(JsVar *parent, JsVar *props) { if (!jsvIsObject(parent)) { jsExceptionHere(JSET_ERROR, "First argument must be an object, got %t\n", parent); return 0; } if (!jsvIsObject(props)) { jsExceptionHere(JSET_ERROR, "Second argument must be an object, got %t\n", props); return 0; } JsvObjectIterator it; jsvObjectIteratorNew(&it, props); while (jsvObjectIteratorHasValue(&it)) { JsVar *name = jsvObjectIteratorGetKey(&it); JsVar *desc = jsvObjectIteratorGetValue(&it); jsvUnLock3(jswrap_object_defineProperty(parent, name, desc), name, desc); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); return jsvLockAgain(parent); }
/** This gets called when the destination closes and we need to clean up */ static void jswrap_pipe_close_listener(JsVar *destination, const char *name) { if (!jsvIsObject(destination)) return; // try and find it... JsVar *arr = pipeGetArray(false); if (arr) { JsvObjectIterator it; jsvObjectIteratorNew(&it, arr); while (jsvObjectIteratorHasValue(&it)) { JsVar *pipe = jsvObjectIteratorGetValue(&it); JsVar *dst = jsvObjectGetChild(pipe,name,0); if (dst == destination) { // found it! said wait to false handlePipeClose(arr, &it, pipe); } jsvUnLock(dst); jsvUnLock(pipe); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); jsvUnLock(arr); } }
/** This gets called when a pipe destination drains itself */ static void jswrap_pipe_drain_listener(JsVar *destination) { if (!jsvIsObject(destination)) return; // try and find it... JsVar *arr = pipeGetArray(false); if (arr) { JsvObjectIterator it; jsvObjectIteratorNew(&it, arr); while (jsvObjectIteratorHasValue(&it)) { JsVar *pipe = jsvObjectIteratorGetValue(&it); JsVar *dst = jsvObjectGetChild(pipe,"destination",0); if (dst == destination) { // found it! said wait to false jsvUnLock(jsvObjectSetChild(pipe,"drainWait",jsvNewFromBool(false))); } jsvUnLock(dst); jsvUnLock(pipe); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); jsvUnLock(arr); } }
/* 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); }
/*JSON{ "type" : "kill", "generate" : "jswrap_waveform_kill", "ifndef" : "SAVE_ON_FLASH" }*/ void jswrap_waveform_kill() { // be sure to remove all waveforms... JsVar *waveforms = jsvObjectGetChild(execInfo.hiddenRoot, JSI_WAVEFORM_NAME, 0); if (waveforms) { JsvObjectIterator it; jsvObjectIteratorNew(&it, waveforms); while (jsvObjectIteratorHasValue(&it)) { JsVar *waveform = jsvObjectIteratorGetValue(&it); bool running = jsvGetBoolAndUnLock(jsvObjectGetChild(waveform, "running", 0)); if (running) { JsVar *buffer = jswrap_waveform_getBuffer(waveform,0,0); if (!jstStopBufferTimerTask(buffer)) { jsExceptionHere(JSET_ERROR, "Waveform couldn't be stopped"); } jsvUnLock(buffer); } jsvUnLock(waveform); // if not running, remove waveform from this list jsvObjectIteratorRemoveAndGotoNext(&it, waveforms); } jsvObjectIteratorFree(&it); jsvUnLock(waveforms); } }
/*JSON{ "type" : "method", "class" : "Object", "name" : "emit", "generate" : "jswrap_object_emit", "params" : [ ["event","JsVar","The name of the event, for instance 'data'"], ["args","JsVarArray","Optional arguments"] ] } Call the event listeners for this object, for instance ```http.emit('data', 'Foo')```. See Node.js's EventEmitter. */ void jswrap_object_emit(JsVar *parent, JsVar *event, JsVar *argArray) { if (!jsvHasChildren(parent)) { jsWarn("Parent must be an object - not a String, Integer, etc."); return; } if (!jsvIsString(event)) { jsWarn("First argument to EventEmitter.emit(..) must be a string"); return; } JsVar *eventName = jsvVarPrintf(JS_EVENT_PREFIX"%s",event); if (!eventName) return; // no memory // extract data const unsigned int MAX_ARGS = 4; JsVar *args[MAX_ARGS]; unsigned int n = 0; JsvObjectIterator it; jsvObjectIteratorNew(&it, argArray); while (jsvObjectIteratorHasValue(&it)) { if (n>=MAX_ARGS) { jsWarn("Too many arguments"); break; } args[n++] = jsvObjectIteratorGetValue(&it); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); JsVar *callback = jsvSkipNameAndUnLock(jsvFindChildFromVar(parent, eventName, 0)); jsvUnLock(eventName); if (callback) jsiQueueEvents(parent, callback, args, (int)n); jsvUnLock(callback); // unlock jsvUnLockMany(n, args); }
/*JSON{ "type":"method", "class": "Object", "name" : "removeAllListeners", "description" : ["Removes all listeners, or those of the specified event."], "generate" : "jswrap_object_removeAllListeners", "params" : [ [ "event", "JsVar", "The name of the event, for instance 'data'"] ] }*/ void jswrap_object_removeAllListeners(JsVar *parent, JsVar *event) { if (!jsvIsObject(parent)) { jsWarn("Parent must be a proper object - not a String, Integer, etc."); return; } if (jsvIsString(event)) { // remove the whole child containing listeners char eventName[16] = "#on"; jsvGetString(event, &eventName[3], sizeof(eventName)-4); JsVar *eventList = jsvFindChildFromString(parent, eventName, true); if (eventList) { jsvRemoveChild(parent, eventList); jsvUnLock(eventList); } } else if (jsvIsUndefined(event)) { // Eep. We must remove everything beginning with '#on' JsObjectIterator it; jsvObjectIteratorNew(&it, parent); while (jsvObjectIteratorHasElement(&it)) { JsVar *key = jsvObjectIteratorGetKey(&it); jsvObjectIteratorNext(&it); if (jsvIsString(key) && key->varData.str[0]=='#' && key->varData.str[1]=='o' && key->varData.str[2]=='n') { // begins with #on - we must kill it jsvRemoveChild(parent, key); } jsvUnLock(key); } jsvObjectIteratorFree(&it); } else { jsWarn("First argument to EventEmitter.removeAllListeners(..) must be a string, or undefined"); return; } }