/*JSON{ "type" : "staticmethod", "class" : "Object", "name" : "getOwnPropertyDescriptor", "generate" : "jswrap_object_getOwnPropertyDescriptor", "params" : [ ["obj","JsVar","The object"], ["name","JsVar","The name of the property"] ], "return" : ["JsVar","An object with a description of the property. The values of writable/enumerable/configurable may not be entirely correct due to Espruino's implementation."] } Get information on the given property in the object, or undefined */ JsVar *jswrap_object_getOwnPropertyDescriptor(JsVar *parent, JsVar *name) { if (!jswrap_object_hasOwnProperty(parent, name)) return 0; JsVar *propName = jsvAsArrayIndex(name); JsVar *varName = jspGetVarNamedField(parent, propName, true); jsvUnLock(propName); assert(varName); // we had it! (apparently) if (!varName) return 0; JsVar *obj = jsvNewObject(); if (!obj) { jsvUnLock(varName); return 0; } //jsvTrace(varName, 5); JsVar *var = jsvSkipName(varName); bool isBuiltIn = jsvIsNewChild(varName); JsvIsInternalChecker checkerFunction = jsvGetInternalFunctionCheckerFor(parent); jsvObjectSetChild(obj, "value", var); jsvObjectSetChildAndUnLock(obj, "writable", jsvNewFromBool(true)); jsvObjectSetChildAndUnLock(obj, "enumerable", jsvNewFromBool(!checkerFunction || !checkerFunction(varName))); jsvObjectSetChildAndUnLock(obj, "configurable", jsvNewFromBool(!isBuiltIn)); jsvUnLock2(var, varName); return obj; }
/*JSON{ "type" : "method", "class" : "Object", "name" : "removeListener", "generate" : "jswrap_object_removeListener", "params" : [ ["event","JsVar","The name of the event, for instance 'data'"], ["listener","JsVar","The listener to remove"] ] } Removes the specified event listener. ``` function foo(d) { console.log(d); } Serial1.on("data", foo); Serial1.removeListener("data", foo); ``` */ void jswrap_object_removeListener(JsVar *parent, JsVar *event, JsVar *callback) { 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 *eventListName = jsvFindChildFromVar(parent, eventName, true); jsvUnLock(eventName); JsVar *eventList = jsvSkipName(eventListName); if (eventList) { if (eventList == callback) { // there's no array, it was a single item jsvRemoveChild(parent, eventListName); } else if (jsvIsArray(eventList)) { // it's an array, search for the index JsVar *idx = jsvGetArrayIndexOf(eventList, callback, true); if (idx) { jsvRemoveChild(eventList, idx); jsvUnLock(idx); } } jsvUnLock(eventList); } jsvUnLock(eventListName); } else { jsWarn("First argument to EventEmitter.removeListener(..) must be a string"); return; } }
/*JSON{ "type":"function", "name" : "require", "description" : "Load the given module, and return the exported functions", "generate" : "jswrap_require", "params" : [ [ "moduleName", "JsVar", "A String containing the name of the given module"] ], "return" : ["JsVar", "The result of evaluating the string"] }*/ JsVar *jswrap_require(JsVar *moduleName) { if (!jsvIsString(moduleName)) { jsWarn("Expecting a module name as a string, but got %t", moduleName); return 0; } // Search to see if we have already loaded this module JsVar *moduleList = jswrap_modules_getModuleList(); if (!moduleList) return 0; // out of memory JsVar *moduleExportName = jsvFindChildFromVar(moduleList, moduleName, true); jsvUnLock(moduleList); if (!moduleExportName) return 0; // out of memory JsVar *moduleExport = jsvSkipName(moduleExportName); if (moduleExport) { // Found the module! jsvUnLock(moduleExportName); return moduleExport; } // Now check if it is built-in char moduleNameBuf[32]; jsvGetString(moduleName, moduleNameBuf, sizeof(moduleNameBuf)); if (jswIsBuiltInLibrary(moduleNameBuf)) { // create a 'fake' module that Espruino can use to map its built-in functions against moduleExport = jspNewBuiltin(moduleNameBuf); } else { // Now try and load it JsVar *fileContents = 0; //if (jsvIsStringEqual(moduleName,"http")) {} //if (jsvIsStringEqual(moduleName,"fs")) {} #ifdef USE_FILESYSTEM JsVar *modulePath = jsvNewFromString( #ifdef LINUX "node_modules/" #else "NODE_M~1/" #endif ); if (!modulePath) { jsvUnLock(moduleExportName); return 0; } // out of memory jsvAppendStringVarComplete(modulePath, moduleName); jsvAppendString(modulePath,".js"); fileContents = wrap_fat_readFile(modulePath); jsvUnLock(modulePath); #endif if (!fileContents || jsvIsStringEqual(fileContents,"")) { jsvUnLock(moduleExportName); jsvUnLock(fileContents); jsWarn("Module not found"); return 0; } moduleExport = jspEvaluateModule(jsiGetParser(), fileContents); jsvUnLock(fileContents); } assert(moduleExport); jsvSetValueOfName(moduleExportName, moduleExport); // save in cache jsvUnLock(moduleExportName); return moduleExport; }
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 serverNew(ST_HTTP, callback); }
static JsVar* fsGetArray(const char *name, bool create) { JsVar *arrayName = jsvFindChildFromString(execInfo.root, name, create); JsVar *arr = jsvSkipName(arrayName); if (!arr && create) { arr = jsvNewWithFlags(JSV_ARRAY); jsvSetValueOfName(arrayName, arr); } jsvUnLock(arrayName); return arr; }
/*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; }
static JsVar *jswrap_modules_getModuleList() { JsVar *moduleListName = jsvFindChildFromString(jsiGetParser()->root, JSPARSE_MODULE_CACHE_NAME, true); if (!moduleListName) return 0; // out of memory JsVar *moduleList = jsvSkipName(moduleListName); if (!moduleList) { moduleList = jsvNewWithFlags(JSV_OBJECT); if (!moduleList) { jsvUnLock(moduleListName); return 0; } // out of memory jsvSetValueOfName(moduleListName, moduleList); // no need to unlock } jsvUnLock(moduleListName); return moduleList; }
static void fileSetVar(JsFile *file) { JsVar *fHandle = jsvFindChildFromString(file->fileVar, JS_FS_DATA_NAME, true); JsVar *data = jsvSkipName(fHandle); if (!data) { data = jsvNewStringOfLength(sizeof(JsFileData)); jsvSetValueOfName(fHandle, data); } jsvUnLock(fHandle); assert(data); jsvSetString(data, (char*)&file->data, sizeof(JsFileData)); jsvUnLock(data); }
void graphicsSetVar(JsGraphics *gfx) { JsVar *dataname = jsvFindChildFromString(gfx->graphicsVar, JS_HIDDEN_CHAR_STR"gfx", true); JsVar *data = jsvSkipName(dataname); if (!data) { data = jsvNewStringOfLength(sizeof(JsGraphicsData)); jsvSetValueOfName(dataname, data); } jsvUnLock(dataname); assert(data); jsvSetString(data, (char*)&gfx->data, sizeof(JsGraphicsData)); jsvUnLock(data); }
/*JSON{ "type":"function", "name" : "digitalWrite", "description" : ["Set the digital value of the given pin", "If pin is an array of pins, eg. ```[A2,A1,A0]``` the value will be treated as an integer where the first array element is the MSB" ], "generate" : "jswrap_io_digitalWrite", "params" : [ [ "pin", "JsVar", "The pin to use"], [ "value", "int", "Whether to pulse high (true) or low (false)"] ] }*/ void jswrap_io_digitalWrite(JsVar *pinVar, JsVarInt value) { if (jsvIsArray(pinVar)) { JsVarRef pinName = pinVar->lastChild; // NOTE: start at end and work back! while (pinName) { JsVar *pinNamePtr = jsvLock(pinName); JsVar *pinPtr = jsvSkipName(pinNamePtr); jshPinOutput(jshGetPinFromVar(pinPtr), value&1); jsvUnLock(pinPtr); pinName = pinNamePtr->prevSibling; jsvUnLock(pinNamePtr); value = value>>1; // next bit down } } else {
/*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); }
/*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); } }
/*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); } }
/*JSON{ "type" : "function", "name" : "digitalWrite", "generate" : "jswrap_io_digitalWrite", "params" : [ ["pin", "JsVar","The pin to use"], ["value", "int","Whether to pulse high (true) or low (false)"] ] } Set the digital value of the given pin. **Note:** if you didn't call `pinMode` beforehand then this function will also reset pin's state to `"output"` If pin argument is an array of pins (eg. `[A2,A1,A0]`) the value argument will be treated as an array of bits where the last array element is the least significant bit. In this case, pin values are set least significant bit first (from the right-hand side of the array of pins). This means you can use the same pin multiple times, for example `digitalWrite([A1,A1,A0,A0],0b0101)` would pulse A0 followed by A1. If the pin argument is an object with a `write` method, the `write` method will be called with the value passed through. */ void jswrap_io_digitalWrite( JsVar *pinVar, //!< A pin or pins. JsVarInt value //!< The value of the output. ) { // Handle the case where it is an array of pins. if (jsvIsArray(pinVar)) { JsVarRef pinName = jsvGetLastChild(pinVar); // NOTE: start at end and work back! while (pinName) { JsVar *pinNamePtr = jsvLock(pinName); JsVar *pinPtr = jsvSkipName(pinNamePtr); jshPinOutput(jshGetPinFromVar(pinPtr), value&1); jsvUnLock(pinPtr); pinName = jsvGetPrevSibling(pinNamePtr); jsvUnLock(pinNamePtr); value = value>>1; // next bit down } } else if (jsvIsObject(pinVar)) {
/*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; }
/*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; }
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; }
/*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')"); } }
/*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); }