/*JSON{ "type":"function", "name" : "trace", "ifndef" : "SAVE_ON_FLASH", "description" : "Output debugging information", "generate" : "jswrap_interface_trace", "params" : [ [ "root", "JsVar", "The symbol to output (optional). If nothing is specified, everything will be output"] ] }*/ void jswrap_interface_trace(JsVar *root) { if (jsvIsUndefined(root)) { jsvTrace(jsvGetRef(execInfo.root), 0); } else { jsvTrace(jsvGetRef(root), 0); } }
/*JSON{ "type":"function", "name" : "trace", "ifndef" : "SAVE_ON_FLASH", "description" : "Output debugging information", "generate" : "jswrap_interface_trace", "params" : [ [ "root", "JsVarName", "The symbol to output (optional). If nothing is specified, everything will be output"] ] }*/ void jswrap_interface_trace(JsVar *root) { if (jsvIsUndefined(root)) { jsvTrace(jsvGetRef(jsiGetParser()->root), 0); } else { jsvTrace(jsvGetRef(root), 0); } }
void jsvStringIteratorAppend(JsvStringIterator *it, char ch) { if (!it->var) return; if (it->charsInVar>0) { assert(it->charIdx+1 == it->charsInVar /* check at end */); it->charIdx++; } else assert(it->charIdx == 0); if (it->charIdx >= jsvGetMaxCharactersInVar(it->var)) { assert(!jsvGetLastChild(it->var)); JsVar *next = jsvNewWithFlags(JSV_STRING_EXT_0); if (!next) { jsvUnLock(it->var); it->var = 0; it->charIdx = 0; return; // out of memory } // we don't ref, because StringExts are never reffed as they only have one owner (and ALWAYS have an owner) jsvSetLastChild(it->var, jsvGetRef(next)); jsvUnLock(it->var); it->var = next; it->varIndex += it->charIdx; it->charIdx = 0; // it's new, so empty } it->var->varData.str[it->charIdx] = ch; it->charsInVar = it->charIdx+1; jsvSetCharactersInVar(it->var, it->charsInVar); }
void jsvStringIteratorAppend(JsvStringIterator *it, char ch) { if (!it->var) return; if (it->charsInVar>0) { assert(it->charIdx+1 == it->charsInVar /* check at end */); it->charIdx++; } else assert(it->charIdx == 0); /* Note: jsvGetMaxCharactersInVar will return the wrong length when * applied to flat strings, but we don't care because the length will * be smaller than charIdx, which will force a new string to be * appended onto the end */ if (it->charIdx >= jsvGetMaxCharactersInVar(it->var)) { assert(!jsvGetLastChild(it->var)); JsVar *next = jsvNewWithFlags(JSV_STRING_EXT_0); if (!next) { jsvUnLock(it->var); it->var = 0; it->ptr = 0; it->charIdx = 0; return; // out of memory } // we don't ref, because StringExts are never reffed as they only have one owner (and ALWAYS have an owner) jsvSetLastChild(it->var, jsvGetRef(next)); jsvUnLock(it->var); it->var = next; it->ptr = &next->varData.str[0]; it->varIndex += it->charIdx; it->charIdx = 0; // it's new, so empty } it->ptr[it->charIdx] = ch; it->charsInVar = it->charIdx+1; jsvSetCharactersInVar(it->var, it->charsInVar); }
JsVar *jslNewStringFromLexer(JslCharPos *charFrom, size_t charTo) { // Original method - just copy it verbatim size_t maxLength = charTo + 1 - jsvStringIteratorGetIndex(&charFrom->it); assert(maxLength>0); // will fail if 0 // Try and create a flat string first JsVar *var = 0; if (maxLength > JSV_FLAT_STRING_BREAK_EVEN) { var = jsvNewFlatStringOfLength((unsigned int)maxLength); if (var) { // Flat string char *flatPtr = jsvGetFlatStringPointer(var); *(flatPtr++) = charFrom->currCh; JsvStringIterator it = jsvStringIteratorClone(&charFrom->it); while (jsvStringIteratorHasChar(&it) && (--maxLength>0)) { *(flatPtr++) = jsvStringIteratorGetChar(&it); jsvStringIteratorNext(&it); } jsvStringIteratorFree(&it); return var; } } // Non-flat string... var = jsvNewFromEmptyString(); if (!var) { // out of memory return 0; } //jsvAppendStringVar(var, lex->sourceVar, charFrom->it->index, (int)(charTo-charFrom)); JsVar *block = jsvLockAgain(var); block->varData.str[0] = charFrom->currCh; size_t blockChars = 1; size_t l = maxLength; // now start appending JsvStringIterator it = jsvStringIteratorClone(&charFrom->it); while (jsvStringIteratorHasChar(&it) && (--maxLength>0)) { char ch = jsvStringIteratorGetChar(&it); if (blockChars >= jsvGetMaxCharactersInVar(block)) { jsvSetCharactersInVar(block, blockChars); JsVar *next = jsvNewWithFlags(JSV_STRING_EXT_0); if (!next) break; // out of memory // we don't ref, because StringExts are never reffed as they only have one owner (and ALWAYS have an owner) jsvSetLastChild(block, jsvGetRef(next)); jsvUnLock(block); block = next; blockChars=0; // it's new, so empty } block->varData.str[blockChars++] = ch; jsvStringIteratorNext(&it); } jsvSetCharactersInVar(block, blockChars); jsvUnLock(block); // Just make sure we only assert if there's a bug here. If we just ran out of memory or at end of string it's ok assert((l == jsvGetStringLength(var)) || (jsErrorFlags&JSERR_MEMORY) || !jsvStringIteratorHasChar(&it)); jsvStringIteratorFree(&it); return var; }
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; }
/*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) { JsvArrayIterator it; jsvArrayIteratorNew(&it, waveforms); while (jsvArrayIteratorHasElement(&it)) { JsVar *waveform = jsvArrayIteratorGetElement(&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; jsvUnLock(jsvObjectSetChild(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; JsVar *oldBuffer = jsvObjectGetChild(waveform, "currentBuffer", JSV_INTEGER); if (jsvGetInteger(oldBuffer) !=currentBuffer) { // buffers have changed - fire off a 'buffer' event with the buffer that needs to be filled jsvSetInteger(oldBuffer, currentBuffer); JsVar *arrayBuffer = jsvObjectGetChild(waveform, (currentBuffer==0) ? "buffer" : "buffer2", 0); jsiQueueObjectCallbacks(waveform, "#onbuffer", &arrayBuffer, 1); jsvUnLock(arrayBuffer); } jsvUnLock(oldBuffer); } } jsvUnLock(buffer); } jsvUnLock(waveform); // if not running, remove waveform from this list if (!running) jsvArrayIteratorRemoveAndGotoNext(&it, waveforms); else jsvArrayIteratorNext(&it); } jsvArrayIteratorFree(&it); jsvUnLock(waveforms); } return false; // no need to stay awake - an IRQ will wake us }
JsVar *jswrap_typedarray_constructor(JsVarDataArrayBufferViewType type, JsVar *arr, JsVarInt byteOffset, JsVarInt length) { JsVar *arrayBuffer = 0; if (jsvIsArrayBuffer(arr)) { arrayBuffer = jsvLockAgain(arr); } else if (jsvIsInt(arr)) { length = jsvGetInteger(arr); byteOffset = 0; arrayBuffer = jswrap_arraybuffer_constructor(JSV_ARRAYBUFFER_GET_SIZE(type)*length); } else if (jsvIsArray(arr)) { length = jsvGetArrayLength(arr); byteOffset = 0; arrayBuffer = jswrap_arraybuffer_constructor(JSV_ARRAYBUFFER_GET_SIZE(type)*length); // later on we'll populate this } if (!arrayBuffer) { jsError("Unsupported first argument\n"); return 0; } if (length<=0) length = (JsVarInt)jsvGetArrayBufferLength(arrayBuffer) / JSV_ARRAYBUFFER_GET_SIZE(type); 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; typedArr->firstChild = jsvGetRef(jsvRef(arrayBuffer)); if (jsvIsArray(arr)) { // if we were given an array, populate this ArrayBuffer JsvArrayIterator it; jsvArrayIteratorNew(&it, arr); while (jsvArrayIteratorHasElement(&it)) { JsVar *idx = jsvArrayIteratorGetIndex(&it); if (jsvIsInt(idx)) { JsVar *val = jsvArrayIteratorGetElement(&it); jsvArrayBufferSet(typedArr, jsvGetInteger(idx), val); jsvUnLock(val); } jsvUnLock(idx); jsvArrayIteratorNext(&it); } jsvArrayIteratorFree(&it); } } jsvUnLock(arrayBuffer); return typedArr; }
bool run_test(const char *filename) { printf("----------------------------------\r\n"); printf("----------------------------- TEST %s \r\n", filename); char *buffer = (char *)read_file(filename); if (!buffer) return (false); jshInit(); jsiInit(false /* do not autoload!!! */); jspAddNativeFunction(jsiGetParser(), "function quit()", nativeQuit); jspAddNativeFunction(jsiGetParser(), "function interrupt()", nativeInterrupt); jsvUnLock(jspEvaluate(jsiGetParser(), buffer )); isRunning = true; while (isRunning && jsiHasTimers()) jsiLoop(); JsVar *result = jsvObjectGetChild(jsiGetParser()->root, "result", 0/*no create*/); bool pass = jsvGetBool(result); jsvUnLock(result); if (pass) printf("----------------------------- PASS %s\r\n", filename); else { printf("----------------------------------\r\n"); printf("----------------------------- FAIL %s <-------\r\n", filename); jsvTrace(jsvGetRef(jsiGetParser()->root), 0); printf("----------------------------- FAIL %s <-------\r\n", filename); printf("----------------------------------\r\n"); } printf("BEFORE: %d Memory Records Used\r\n", jsvGetMemoryUsage()); // jsvTrace(jsiGetParser()->root, 0); jsiKill(); printf("AFTER: %d Memory Records Used\r\n", jsvGetMemoryUsage()); jsvGarbageCollect(); printf("AFTER GC: %d Memory Records Used (should be 0!)\r\n", jsvGetMemoryUsage()); jsvShowAllocated(); jshKill(); //jsvDottyOutput(); printf("\r\n"); free(buffer); return pass; }
JsVar *_jswrap_array_map_or_forEach(JsVar *parent, JsVar *funcVar, JsVar *thisVar, bool isMap) { if (!jsvIsFunction(funcVar)) { jsError("Array.map's first argument should be a function"); return 0; } if (!jsvIsUndefined(thisVar) && !jsvIsObject(thisVar)) { jsError("Arraymap's second argument should be undefined, or an object"); return 0; } JsVar *array = 0; if (isMap) array = jsvNewWithFlags(JSV_ARRAY); if (array || !isMap) { JsVarRef childRef = parent->firstChild; while (childRef) { JsVar *child = jsvLock(childRef); if (jsvIsInt(child)) { JsVar *args[3], *mapped; args[0] = jsvLock(child->firstChild); // child is a variable name, create a new variable for the index args[1] = jsvNewFromInteger(jsvGetInteger(child)); args[2] = parent; mapped = jspeFunctionCall(funcVar, 0, thisVar, false, 3, args); jsvUnLock(args[0]); jsvUnLock(args[1]); if (mapped) { if (isMap) { JsVar *name = jsvCopyNameOnly(child, false/*linkChildren*/, true/*keepAsName*/); if (name) { // out of memory? name->firstChild = jsvGetRef(jsvRef(mapped)); jsvAddName(array, name); jsvUnLock(name); } } jsvUnLock(mapped); } } childRef = child->nextSibling; jsvUnLock(child); } } return array; }
/*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":"constructor", "class": "ArrayBuffer", "name": "ArrayBuffer", "description" : "Create an Array Buffer object", "generate" : "jswrap_arraybuffer_constructor", "params" : [ [ "byteLength", "int", "The length in Bytes" ] ], "return" : [ "JsVar", "An ArrayBuffer object" ] }*/ JsVar *jswrap_arraybuffer_constructor(JsVarInt byteLength) { if (byteLength <= 0 || byteLength>65535) { jsError("Invalid length for ArrayBuffer\n"); return 0; } if (byteLength > JSV_ARRAYBUFFER_MAX_LENGTH) { jsError("ArrayBuffer too long\n"); return 0; } JsVar *arrData = jsvNewStringOfLength((unsigned int)byteLength); if (!arrData) return 0; JsVar *arr = jsvNewWithFlags(JSV_ARRAYBUFFER); if (!arr) { jsvUnLock(arrData); return 0; } arr->firstChild = jsvGetRef(jsvRef(arrData)); jsvUnLock(arrData); arr->varData.arraybuffer.type = ARRAYBUFFERVIEW_ARRAYBUFFER; arr->varData.arraybuffer.byteOffset = 0; arr->varData.arraybuffer.length = (unsigned short)byteLength; return arr; }
JsVar *jslNewFromLexer(struct JsLex *lex, JslCharPos *charFrom, size_t charTo) { // Create a var JsVar *var = jsvNewFromEmptyString(); if (!var) { // out of memory return 0; } //jsvAppendStringVar(var, lex->sourceVar, charFrom->it->index, (int)(charTo-charFrom)); size_t maxLength = charTo - jsvStringIteratorGetIndex(&charFrom->it); JsVar *block = jsvLockAgain(var); block->varData.str[0] = charFrom->currCh; size_t blockChars = 1; // now start appending JsvStringIterator it = jsvStringIteratorClone(&charFrom->it); while (jsvStringIteratorHasChar(&it) && (maxLength-->0)) { char ch = jsvStringIteratorGetChar(&it); if (blockChars >= jsvGetMaxCharactersInVar(block)) { jsvSetCharactersInVar(block, blockChars); JsVar *next = jsvNewWithFlags(JSV_STRING_EXT); if (!next) break; // out of memory // we don't ref, because StringExts are never reffed as they only have one owner (and ALWAYS have an owner) block->lastChild = jsvGetRef(next); jsvUnLock(block); block = next; blockChars=0; // it's new, so empty } block->varData.str[blockChars++] = ch; jsvStringIteratorNext(&it); } jsvStringIteratorFree(&it); jsvSetCharactersInVar(block, blockChars); jsvUnLock(block); return var; }