/*JSON{ "type" : "staticmethod", "class" : "JSON", "name" : "parse", "generate" : "jswrap_json_parse", "params" : [ ["string","JsVar","A JSON string"] ], "return" : ["JsVar","The JavaScript object created by parsing the data string"] } Parse the given JSON string into a JavaScript object NOTE: This implementation uses eval() internally, and as such it is unsafe as it can allow arbitrary JS commands to be executed. */ JsVar *jswrap_json_parse(JsVar *v) { JsLex lex; jslInit(&lex, v); JsVar *res = jswrap_json_parse_internal(&lex); jslKill(&lex); return res; }
/*JSON{ "type" : "staticmethod", "class" : "JSON", "name" : "parse", "generate" : "jswrap_json_parse", "params" : [ ["string","JsVar","A JSON string"] ], "return" : ["JsVar","The JavaScript object created by parsing the data string"] } Parse the given JSON string into a JavaScript object NOTE: This implementation uses eval() internally, and as such it is unsafe as it can allow arbitrary JS commands to be executed. */ JsVar *jswrap_json_parse(JsVar *v) { JsLex lex; JsVar *str = jsvAsString(v); JsLex *oldLex = jslSetLex(&lex); jslInit(str); jsvUnLock(str); JsVar *res = jswrap_json_parse_internal(); jslKill(); jslSetLex(oldLex); return res; }
/*JSON{ "type" : "staticmethod", "ifndef" : "SAVE_ON_FLASH", "class" : "E", "name" : "nativeCall", "generate" : "jswrap_espruino_nativeCall", "params" : [ ["addr","int","The address in memory of the function"], ["sig","JsVar","The signature of the call, `returnType (arg1,arg2,...)`. Allowed types are `void`,`bool`,`int`,`double`,`Pin`,`JsVar`"] ], "return" : ["JsVar","The native function"] } ADVANCED: This is a great way to crash Espruino if you're not sure what you are doing Create a native function that executes the code at the given address. Eg. `E.nativeCall(0x08012345,'double (double,double)')(1.1, 2.2)` If you're executing a thumb function, you'll almost certainly need to set the bottom bit of the address to 1. Note it's not guaranteed that the call signature you provide can be used - it has to be something that a function in Espruino already uses. */ JsVar *jswrap_espruino_nativeCall(JsVarInt addr, JsVar *signature) { unsigned int argTypes = 0; if (jsvIsUndefined(signature)) { // Nothing to do } else if (jsvIsString(signature)) { JsLex lex; jslInit(&lex, signature); int argType; bool ok = true; int argNumber = 0; argType = nativeCallGetCType(&lex); if (argType>=0) argTypes |= (unsigned)argType << (JSWAT_BITS * argNumber++); else ok = false; if (ok) ok = jslMatch(&lex, '('); while (ok && lex.tk!=LEX_EOF && lex.tk!=')') { argType = nativeCallGetCType(&lex); if (argType>=0) { argTypes |= (unsigned)argType << (JSWAT_BITS * argNumber++); if (lex.tk!=')') ok = jslMatch(&lex, ','); } else ok = false; } if (ok) ok = jslMatch(&lex, ')'); jslKill(&lex); if (argTypes & (unsigned int)~0xFFFF) ok = false; if (!ok) { jsExceptionHere(JSET_ERROR, "Error Parsing signature at argument number %d", argNumber); return 0; } } else { jsExceptionHere(JSET_ERROR, "Invalid Signature"); return 0; } return jsvNewNativeFunction((void *)(size_t)addr, (unsigned short)argTypes); }
/*JSON{ "type" : "staticmethod", "class" : "Date", "name" : "parse", "generate" : "jswrap_date_parse", "params" : [ ["str","JsVar","A String"] ], "return" : ["float","The number of milliseconds since 1970"] } Parse a date string and return milliseconds since 1970. Data can be either '2011-10-20T14:48:00', '2011-10-20' or 'Mon, 25 Dec 1995 13:30:00 +0430' */ JsVarFloat jswrap_date_parse(JsVar *str) { if (!jsvIsString(str)) return 0; TimeInDay time; time.daysSinceEpoch = 0; time.hour = 0; time.min = 0; time.sec = 0; time.ms = 0; time.zone = 0; CalendarDate date = getCalendarDate(0); JsLex lex; jslInit(&lex, str); if (lex.tk == LEX_ID) { date.month = getMonth(jslGetTokenValueAsString(&lex)); date.dow = getDay(jslGetTokenValueAsString(&lex)); if (date.month>=0) { // Aug 9, 1995 jslGetNextToken(&lex); if (lex.tk == LEX_INT) { date.day = _parse_int(&lex); jslGetNextToken(&lex); if (lex.tk==',') { jslGetNextToken(&lex); if (lex.tk == LEX_INT) { date.year = _parse_int(&lex); jslGetNextToken(&lex); if (lex.tk == LEX_INT) { _parse_time(&lex, &time, 0); } } } } } else if (date.dow>=0) { date.month = 0; jslGetNextToken(&lex); if (lex.tk==',') { jslGetNextToken(&lex); if (lex.tk == LEX_INT) { date.day = _parse_int(&lex); jslGetNextToken(&lex); if (lex.tk == LEX_ID && getMonth(jslGetTokenValueAsString(&lex))>=0) { date.month = getMonth(jslGetTokenValueAsString(&lex)); jslGetNextToken(&lex); if (lex.tk == LEX_INT) { date.year = _parse_int(&lex); jslGetNextToken(&lex); if (lex.tk == LEX_INT) { _parse_time(&lex, &time, 0); } } } } } } else { date.dow = 0; date.month = 0; } } else if (lex.tk == LEX_INT) { // assume 2011-10-10T14:48:00 format date.year = _parse_int(&lex); jslGetNextToken(&lex); if (lex.tk=='-') { jslGetNextToken(&lex); if (lex.tk == LEX_INT) { date.month = _parse_int(&lex) - 1; jslGetNextToken(&lex); if (lex.tk=='-') { jslGetNextToken(&lex); if (lex.tk == LEX_INT) { date.day = _parse_int(&lex); jslGetNextToken(&lex); if (lex.tk == LEX_ID && jslGetTokenValueAsString(&lex)[0]=='T') { _parse_time(&lex, &time, 1); } } } } } } jslKill(&lex); time.daysSinceEpoch = fromCalenderDate(&date); return fromTimeInDay(&time); }
JsVar *jslNewTokenisedStringFromLexer(JslCharPos *charFrom, size_t charTo) { // New method - tokenise functions // save old lex JsLex *oldLex = lex; JsLex newLex; lex = &newLex; // work out length size_t length = 0; jslInit(oldLex->sourceVar); jslSeekToP(charFrom); int lastTk = LEX_EOF; while (lex->tk!=LEX_EOF && jsvStringIteratorGetIndex(&lex->it)<=charTo+1) { if ((lex->tk==LEX_ID || lex->tk==LEX_FLOAT || lex->tk==LEX_INT) && ( lastTk==LEX_ID || lastTk==LEX_FLOAT || lastTk==LEX_INT)) { jsExceptionHere(JSET_SYNTAXERROR, "ID/number following ID/number isn't valid JS"); length = 0; break; } if (lex->tk==LEX_ID || lex->tk==LEX_INT || lex->tk==LEX_FLOAT || lex->tk==LEX_STR || lex->tk==LEX_TEMPLATE_LITERAL) { length += jsvStringIteratorGetIndex(&lex->it)-jsvStringIteratorGetIndex(&lex->tokenStart.it); } else { length++; } lastTk = lex->tk; jslGetNextToken(); } // Try and create a flat string first JsVar *var = jsvNewStringOfLength((unsigned int)length, NULL); if (var) { // out of memory JsvStringIterator dstit; jsvStringIteratorNew(&dstit, var, 0); // now start appending jslSeekToP(charFrom); while (lex->tk!=LEX_EOF && jsvStringIteratorGetIndex(&lex->it)<=charTo+1) { if (lex->tk==LEX_ID || lex->tk==LEX_INT || lex->tk==LEX_FLOAT || lex->tk==LEX_STR || lex->tk==LEX_TEMPLATE_LITERAL) { jsvStringIteratorSetCharAndNext(&dstit, lex->tokenStart.currCh); JsvStringIterator it = jsvStringIteratorClone(&lex->tokenStart.it); while (jsvStringIteratorGetIndex(&it)+1 < jsvStringIteratorGetIndex(&lex->it)) { jsvStringIteratorSetCharAndNext(&dstit, jsvStringIteratorGetChar(&it)); jsvStringIteratorNext(&it); } jsvStringIteratorFree(&it); } else { jsvStringIteratorSetCharAndNext(&dstit, (char)lex->tk); } lastTk = lex->tk; jslGetNextToken(); } jsvStringIteratorFree(&dstit); } // restore lex jslKill(); lex = oldLex; return var; }