void jslSeekToP(JsLex *lex, JslCharPos *seekToChar) { jsvStringIteratorFree(&lex->it); lex->it = jsvStringIteratorClone(&seekToChar->it); lex->currCh = seekToChar->currCh; lex->tokenStart.it.var = 0; lex->tokenStart.currCh = 0; jslGetNextToken(lex); }
/// Match, and return true on success, false on failure bool jslMatch(int expected_tk) { if (lex->tk != expected_tk) { jslMatchError(expected_tk); return false; } jslGetNextToken(); return true; }
/// Match, and return true on success, false on failure bool jslMatch(int expected_tk) { if (lex->tk != expected_tk) { char gotStr[20]; char expStr[20]; 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(); return false; } jslGetNextToken(); return true; }
void jslSeekToP(JslCharPos *seekToChar) { if (lex->it.var) jsvLockAgain(lex->it.var); // see jslGetNextCh jsvStringIteratorFree(&lex->it); lex->it = jsvStringIteratorClone(&seekToChar->it); jsvUnLock(lex->it.var); // see jslGetNextCh lex->currCh = seekToChar->currCh; lex->tokenStart.it.var = 0; lex->tokenStart.currCh = 0; jslGetNextToken(); }
/// 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; }
static bool _parse_time(JsLex *lex, TimeInDay *time, int initialChars) { time->hour = (int)stringToIntWithRadix(&jslGetTokenValueAsString(lex)[initialChars], 10, 0); jslGetNextToken(lex); if (lex->tk==':') { jslGetNextToken(lex); if (lex->tk == LEX_INT) { time->min = _parse_int(lex); jslGetNextToken(lex); if (lex->tk==':') { jslGetNextToken(lex); if (lex->tk == LEX_INT || lex->tk == LEX_FLOAT) { JsVarFloat f = stringToFloat(jslGetTokenValueAsString(lex)); time->sec = (int)f; time->ms = (int)(f*1000) % 1000; jslGetNextToken(lex); if (lex->tk == LEX_ID && strcmp(jslGetTokenValueAsString(lex),"GMT")==0) { jslGetNextToken(lex); } if (lex->tk == '+' || lex->tk == '-') { int sign = lex->tk == '+' ? 1 : -1; jslGetNextToken(lex); if (lex->tk == LEX_INT) { int i = _parse_int(lex); // correct the fact that it's HHMM and turn it into just minutes i = (i%100) + ((i/100)*60); time->zone = i*sign; jslGetNextToken(lex); } } return true; } } } } return false; }
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 } } }
JsVar *jswrap_json_parse_internal(JsLex *lex) { 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, '-'); jsvUnLock(v); jsvUnLock(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 = jsvNewWithFlags(JSV_ARRAY); if (!arr) return 0; jslGetNextToken(lex); // [ while (lex->tk != ']') { JsVar *value = jswrap_json_parse_internal(lex); if (!value || (lex->tk!=']' && !jslMatch(lex, ','))) { jsvUnLock(value); jsvUnLock(arr); return 0; } jsvArrayPush(arr, value); jsvUnLock(value); } if (!jslMatch(lex, ']')) { jsvUnLock(arr); return 0; } return arr; } case '{': { JsVar *obj = jsvNewWithFlags(JSV_OBJECT); if (!obj) return 0; jslGetNextToken(lex); // { while (lex->tk == LEX_STR) { JsVar *key = jsvAsArrayIndexAndUnLock(jslGetTokenValueAsVar(lex)); jslGetNextToken(lex); JsVar *value = 0; if (!jslMatch(lex, ':') || !(value=jswrap_json_parse_internal(lex)) || (lex->tk!='}' && !jslMatch(lex, ','))) { jsvUnLock(key); jsvUnLock(value); jsvUnLock(obj); return 0; } jsvAddName(obj, jsvMakeIntoVariableName(key, value)); jsvUnLock(value); jsvUnLock(key); } if (!jslMatch(lex, '}')) { jsvUnLock(obj); return 0; } return obj; } default: return 0; // undefined = error } }
/*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); }
static ALWAYS_INLINE void jslPreload() { // set up.. jslGetNextCh(); jslGetNextToken(); }
static inline void jslPreload(JsLex *lex) { // set up.. jslGetNextCh(lex); jslGetNextToken(lex); }
static ALWAYS_INLINE void jslPreload(JsLex *lex) { // set up.. jslGetNextCh(lex); jslGetNextToken(lex); }
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; }