void jslGetTokenString(char *str, size_t len) { if (lex->tk == LEX_ID) { espruino_snprintf(str, len, "ID:%s", jslGetTokenValueAsString()); } else if (lex->tk == LEX_STR) { espruino_snprintf(str, len, "String:'%s'", jslGetTokenValueAsString()); } else jslTokenAsString(lex->tk, str, len); }
/** When printing out a function, with pretokenise a * character could end up being a special token. This * handles that case. */ void jslFunctionCharAsString(unsigned char ch, char *str, size_t len) { if (ch >= LEX_TOKEN_START) { jslTokenAsString(ch, str, len); } else { str[0] = (char)ch; str[1] = 0; } }
void jslGetTokenString(char *str, size_t len) { if (lex->tk == LEX_ID) { strncpy(str, "ID:", len); strncat(str, jslGetTokenValueAsString(), len); } else if (lex->tk == LEX_STR) { strncpy(str, "String:'", len); strncat(str, jslGetTokenValueAsString(), len); strncat(str, "'", len); } else jslTokenAsString(lex->tk, str, len); }
/* Match failed - report error message */ static void jslMatchError(int expected_tk) { char gotStr[30]; char expStr[30]; jslGetTokenString(gotStr, sizeof(gotStr)); jslTokenAsString(expected_tk, expStr, sizeof(expStr)); size_t oldPos = lex->tokenLastStart; lex->tokenLastStart = jsvStringIteratorGetIndex(&lex->tokenStart.it)-1; jsExceptionHere(JSET_SYNTAXERROR, "Got %s expected %s", gotStr, expStr); lex->tokenLastStart = oldPos; // Sod it, skip this token anyway - stops us looping jslGetNextToken(); }
/// Match, and return true on success, false on failure bool jslMatch(JsLex *lex, int expected_tk) { if (lex->tk != expected_tk) { char gotStr[16]; char expStr[16]; jslGetTokenString(lex, gotStr, sizeof(gotStr)); jslTokenAsString(expected_tk, expStr, sizeof(expStr)); size_t oldPos = lex->tokenLastStart; lex->tokenLastStart = jsvStringIteratorGetIndex(&lex->tokenStart.it)-1; jsExceptionHere(JSET_SYNTAXERROR, "Got %s expected %s", gotStr, expStr); lex->tokenLastStart = oldPos; // Sod it, skip this token anyway - stops us looping jslGetNextToken(lex); return false; } jslGetNextToken(lex); return true; }
/// Match, and return true on success, false on failure bool jslMatch(JsLex *lex, int expected_tk) { if (lex->tk!=expected_tk) { char buf[JS_ERROR_BUF_SIZE]; size_t bufpos = 0; strncpy(&buf[bufpos], "Got ", JS_ERROR_BUF_SIZE-bufpos); bufpos = strlen(buf); jslGetTokenString(lex, &buf[bufpos], JS_ERROR_BUF_SIZE-bufpos); bufpos = strlen(buf); strncpy(&buf[bufpos], " expected ", JS_ERROR_BUF_SIZE-bufpos); bufpos = strlen(buf); jslTokenAsString(expected_tk, &buf[bufpos], JS_ERROR_BUF_SIZE-bufpos); jsErrorAt(buf, lex, jsvStringIteratorGetIndex(&lex->tokenStart.it)); // Sod it, skip this token anyway - stops us looping jslGetNextToken(lex); return false; } jslGetNextToken(lex); return true; }
JsVar *jswrap_json_parse_internal() { switch (lex->tk) { case LEX_R_TRUE: jslGetNextToken(lex); return jsvNewFromBool(true); case LEX_R_FALSE: jslGetNextToken(lex); return jsvNewFromBool(false); case LEX_R_NULL: jslGetNextToken(lex); return jsvNewWithFlags(JSV_NULL); case '-': { jslGetNextToken(lex); if (lex->tk!=LEX_INT && lex->tk!=LEX_FLOAT) return 0; JsVar *v = jswrap_json_parse_internal(lex); JsVar *zero = jsvNewFromInteger(0); JsVar *r = jsvMathsOp(zero, v, '-'); jsvUnLock2(v, zero); return r; } case LEX_INT: { long long v = stringToInt(jslGetTokenValueAsString(lex)); jslGetNextToken(lex); return jsvNewFromLongInteger(v); } case LEX_FLOAT: { JsVarFloat v = stringToFloat(jslGetTokenValueAsString(lex)); jslGetNextToken(lex); return jsvNewFromFloat(v); } case LEX_STR: { JsVar *a = jslGetTokenValueAsVar(lex); jslGetNextToken(lex); return a; } case '[': { JsVar *arr = jsvNewEmptyArray(); if (!arr) return 0; jslGetNextToken(lex); // [ while (lex->tk != ']' && !jspHasError()) { JsVar *value = jswrap_json_parse_internal(lex); if (!value || (lex->tk!=']' && !jslMatch(','))) { jsvUnLock2(value, arr); return 0; } jsvArrayPush(arr, value); jsvUnLock(value); } if (!jslMatch(']')) { jsvUnLock(arr); return 0; } return arr; } case '{': { JsVar *obj = jsvNewObject(); if (!obj) return 0; jslGetNextToken(lex); // { while (lex->tk == LEX_STR && !jspHasError()) { JsVar *key = jsvAsArrayIndexAndUnLock(jslGetTokenValueAsVar(lex)); jslGetNextToken(lex); JsVar *value = 0; if (!jslMatch(':') || !(value=jswrap_json_parse_internal(lex)) || (lex->tk!='}' && !jslMatch(','))) { jsvUnLock3(key, value, obj); return 0; } jsvAddName(obj, jsvMakeIntoVariableName(key, value)); jsvUnLock2(value, key); } if (!jslMatch('}')) { jsvUnLock(obj); return 0; } return obj; } default: { char buf[32]; jslTokenAsString(lex->tk, buf, 32); jsExceptionHere(JSET_SYNTAXERROR, "Expecting a valid value, got %s", buf); return 0; // undefined = error } } }