/* match: search for regexp anywhere in text */ static JsVar *match(char *regexp, JsVar *str, size_t startIndex, bool ignoreCase) { matchInfo info; info.sourceStr = str; info.startIndex = startIndex; info.ignoreCase = ignoreCase; info.rangeMatch = false; info.rangeFirstChar = NO_RANGE; info.groups = 0; JsVar *rmatch; JsvStringIterator txtIt, txtIt2; jsvStringIteratorNew(&txtIt, str, startIndex); /* must look even if string is empty */ txtIt2 = jsvStringIteratorClone(&txtIt); rmatch = matchhere(regexp, &txtIt2, info); jsvStringIteratorFree(&txtIt2); jsvStringIteratorNext(&txtIt); while (!rmatch && jsvStringIteratorHasChar(&txtIt)) { info.startIndex++; txtIt2 = jsvStringIteratorClone(&txtIt); rmatch = matchhere(regexp, &txtIt2, info); jsvStringIteratorFree(&txtIt2); jsvStringIteratorNext(&txtIt); } jsvStringIteratorFree(&txtIt); return rmatch; }
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; }
void jsvArrayBufferIteratorSetValueAndRewind(JsvArrayBufferIterator *it, JsVar *value) { JsvStringIterator oldIt = jsvStringIteratorClone(&it->it); jsvArrayBufferIteratorSetValue(it, value); jsvStringIteratorFree(&it->it); it->it = oldIt; it->hasAccessedElement = false; }
JsVar *jsvArrayBufferIteratorGetValueAndRewind(JsvArrayBufferIterator *it) { JsvStringIterator oldIt = jsvStringIteratorClone(&it->it); JsVar *v = jsvArrayBufferIteratorGetValue(it); jsvStringIteratorFree(&it->it); it->it = oldIt; it->hasAccessedElement = false; return v; }
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); }
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(); }
JsvIterator jsvIteratorClone(JsvIterator *it) { JsvIterator newit; newit.type = it->type; switch (it->type) { case JSVI_OBJECT : newit.it.obj = jsvObjectIteratorClone(&it->it.obj); break; case JSVI_STRING : newit.it.str = jsvStringIteratorClone(&it->it.str); break; case JSVI_ARRAYBUFFER : newit.it.buf = jsvArrayBufferIteratorClone(&it->it.buf); break; default: assert(0); break; } return newit; }
JsvIterator jsvIteratorClone(JsvIterator *it) { JsvIterator newit; newit.type = it->type; switch (it->type) { case JSVI_FULLARRAY: newit.it.obj.index = it->it.obj.index; newit.it.obj.var = jsvLockAgain(it->it.obj.var); // intentionally no break case JSVI_OBJECT : newit.it.obj.it = jsvObjectIteratorClone(&it->it.obj.it); break; case JSVI_STRING : newit.it.str = jsvStringIteratorClone(&it->it.str); break; case JSVI_ARRAYBUFFER : newit.it.buf = jsvArrayBufferIteratorClone(&it->it.buf); break; default: assert(0); break; } return newit; }
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; }
JslCharPos jslCharPosClone(JslCharPos *pos) { JslCharPos p; p.it = jsvStringIteratorClone(&pos->it); p.currCh = pos->currCh; return p; }
/* matchhere: search for regexp at beginning of text. Only handles up to '|' character. Modifies txtIt */ static JsVar *matchhere(char *regexp, JsvStringIterator *txtIt, matchInfo info) { if (jspIsInterrupted()) return 0; if (regexp[0] == '\0' || // end of regex regexp[0] == '|') // end of this 'or' section of regex return matchfound(txtIt, info); if (regexp[0] == '^') { // must be beginning of String if (jsvStringIteratorGetIndex(txtIt)!=0) return 0; // no match if (!jspCheckStackPosition()) return 0; return matchhere(regexp+1, txtIt, info); } // Marker for end of String if (regexp[0] == '$') { if (!jsvStringIteratorHasChar(txtIt)) return matchhere(regexp+1, txtIt, info); else return nomatchfound(regexp+1, info); // not the end, it's a fail } if (regexp[0] == '(') { info.groupStart[info.groups] = jsvStringIteratorGetIndex(txtIt); info.groupEnd[info.groups] = info.groupStart[info.groups]; if (info.groups<MAX_GROUPS) info.groups++; if (!jspCheckStackPosition()) return 0; return matchhere(regexp+1, txtIt, info); } if (regexp[0] == ')') { if (info.groups>0) info.groupEnd[info.groups-1] = jsvStringIteratorGetIndex(txtIt); if (!jspCheckStackPosition()) return 0; return matchhere(regexp+1, txtIt, info); } int charLength; bool charMatched = matchcharacter(regexp, txtIt, &charLength, &info); if (regexp[charLength] == '*' || regexp[charLength] == '+') { char op = regexp[charLength]; if (!charMatched && op=='+') { // with '+' operator it has to match at least once return nomatchfound(®exp[charLength+1], info); } char *regexpAfterStar = regexp+charLength+1; JsvStringIterator txtIt2; // Try and match everything after right now txtIt2 = jsvStringIteratorClone(txtIt); JsVar *lastrmatch = matchhere(regexpAfterStar, &txtIt2, info); jsvStringIteratorFree(&txtIt2); // Otherwise try and match more than one while (jsvStringIteratorHasChar(txtIt) && charMatched) { // We had this character matched, so move on and see if we can match with the new one jsvStringIteratorNext(txtIt); charMatched = matchcharacter(regexp, txtIt, &charLength, &info); // See if we can match after the character... txtIt2 = jsvStringIteratorClone(txtIt); JsVar *rmatch = matchhere(regexpAfterStar, &txtIt2, info); jsvStringIteratorFree(&txtIt2); // can't match with this - use the last one if (rmatch) { jsvUnLock(lastrmatch); lastrmatch = rmatch; } } return lastrmatch; } // This character is matched if (jsvStringIteratorHasChar(txtIt) && charMatched) { jsvStringIteratorNext(txtIt); if (!jspCheckStackPosition()) return 0; return matchhere(regexp+charLength, txtIt, info); } // No match return nomatchfound(®exp[charLength], info); }
/// Clone the iterator ALWAYS_INLINE JsvArrayBufferIterator jsvArrayBufferIteratorClone(JsvArrayBufferIterator *it) { JsvArrayBufferIterator i = *it; i.it = jsvStringIteratorClone(&it->it); return i; }
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; }