static void scStringSlice(const CFunctionsScopePtr &c, void *userdata) { string str = c->getArgument("this")->getString(); int length = c->getArgumentsLength()-((int)userdata & 1); bool slice = ((int)userdata & 2) == 0; int start = c->getArgument("start")->getInt(); int end = (int)str.size(); if(slice && start<0) start = str.size()+start; if(length>1) { end = c->getArgument("end")->getInt(); if(slice && end<0) end = str.size()+end; } if(!slice && end < start) { end^=start; start^=end; end^=start; } if(start<0) start = 0; if(start>=(int)str.size()) c->setReturnVar(c->newScriptVar("")); else if(end <= start) c->setReturnVar(c->newScriptVar("")); else c->setReturnVar(c->newScriptVar(str.substr(start, end-start))); }
static void scArrayPush(const CFunctionsScopePtr &c, void *data) { CScriptVarPtr arr = c->getArgument("this"); uint32_t len = c->getLength(arr); uint32_t args = c->getArgumentsLength(); for (uint32_t i=0; i<args; ++i) c->setProperty(arr, i, c->getArgument(i)); }
static void scRegExpExec(const CFunctionsScopePtr &c, void *) { CScriptVarRegExpPtr This = c->getArgument("this"); if(This) c->setReturnVar(This->exec(c->getArgument("str")->toString())); else c->throwError(TypeError, "Object is not a RegExp-Object in exec(str)"); }
static void scStringConcat(const CFunctionsScopePtr &c, void *userdata) { int length = c->getArgumentsLength(); string str = c->getArgument("this")->getString(); for(int i=(int)userdata; i<length; i++) str.append(c->getArgument(i)->getString()); c->setReturnVar(c->newScriptVar(str)); }
static void scStringConcat(const CFunctionsScopePtr &c, void *userdata) { int length = c->getArgumentsLength(); string str = this2string(c); for(int32_t i=ptr2int32(userdata); i<length; i++) str.append(c->getArgument(i)->toString()); c->setReturnVar(c->newScriptVar(str)); }
static void scStringIndexOf(const CFunctionsScopePtr &c, void *userdata) { string str = c->getArgument("this")->getString(); string search = c->getArgument("search")->getString(); size_t p = (userdata==0) ? str.find(search) : str.rfind(search); int val = (p==string::npos) ? -1 : p; c->setReturnVar(c->newScriptVar(val)); }
static void scTrace(const CFunctionsScopePtr &c, void * userdata) { CTinyJS *js = (CTinyJS*)userdata; if(c->getArgumentsLength()) c->getArgument(0)->trace(); else js->getRoot()->trace("root"); }
static void scCharToInt(const CFunctionsScopePtr &c, void *) { string str = c->getArgument("ch")->toString();; int val = 0; if (str.length()>0) val = (int)str.c_str()[0]; c->setReturnVar(c->newScriptVar(val)); }
static void scArrayPush(const CFunctionsScopePtr &c, void *data) { CScriptVarPtr arr = c->getArgument("this"); int l = arr->getArrayLength(); int args = c->getArgumentsLength(); for (int i=0;i<args;i++) arr->setArrayIndex(l+i, c->getArgument(i)); }
//************************************ // Method: getRegExpData // FullName: getRegExpData // Access: public static // Returns: bool true if regexp-param=RegExp-Object / other false // Qualifier: // Parameter: const CFunctionsScopePtr & c // Parameter: const string & regexp - parameter name of the regexp // Parameter: bool noUndefined - true an undefined regexp aims in "" else in "undefined" // Parameter: const string & flags - parameter name of the flags // Parameter: string & substr - rgexp.source // Parameter: bool & global // Parameter: bool & ignoreCase // Parameter: bool & sticky //************************************ static CScriptVarPtr getRegExpData(const CFunctionsScopePtr &c, const string ®exp, bool noUndefined, const char *flags_argument, string &substr, bool &global, bool &ignoreCase, bool &sticky) { CScriptVarPtr regexpVar = c->getArgument(regexp); if(regexpVar->isRegExp()) { #ifndef NO_REGEXP CScriptVarRegExpPtr RegExp(regexpVar); substr = RegExp->Regexp(); ignoreCase = RegExp->IgnoreCase(); global = RegExp->Global(); sticky = RegExp->Sticky(); return RegExp; #endif /* NO_REGEXP */ } else { substr.clear(); if(!noUndefined || !regexpVar->isUndefined()) substr = regexpVar->toString(); CScriptVarPtr flagVar; if(flags_argument && (flagVar = c->getArgument(flags_argument)) && !flagVar->isUndefined()) { string flags = flagVar->toString(); string::size_type pos = flags.find_first_not_of("gimy"); if(pos != string::npos) { c->throwError(SyntaxError, string("invalid regular expression flag ")+flags[pos]); } global = flags.find_first_of('g')!=string::npos; ignoreCase = flags.find_first_of('i')!=string::npos; sticky = flags.find_first_of('y')!=string::npos; } else global = ignoreCase = sticky = false; } return CScriptVarPtr(); }
static void scArrayRemove(const CFunctionsScopePtr &c, void *data) { CScriptVarPtr obj = c->getArgument("obj"); CScriptVarPtr arr = c->getArgument("this"); int i; vector<int> removedIndices; int l = arr->getArrayLength(); CScriptVarPtr equal = c->constScriptVar(Undefined); for (i=0;i<l;i++) { equal = obj->mathsOp(arr->getArrayIndex(i), LEX_EQUAL); if(equal->toBoolean()) { removedIndices.push_back(i); } } if(removedIndices.size()) { vector<int>::iterator remove_it = removedIndices.begin(); int next_remove = *remove_it; int next_insert = *remove_it++; for (i=next_remove;i<l;i++) { CScriptVarLinkPtr link = arr->findChild(int2string(i)); if(i == next_remove) { if(link) arr->removeLink(link); if(remove_it != removedIndices.end()) next_remove = *remove_it++; } else { if(link) { arr->setArrayIndex(next_insert++, link); arr->removeLink(link); } } } } }
static void scStringCharAt(const CFunctionsScopePtr &c, void *) { string str = this2string(c); int p = c->getArgument("pos")->toNumber().toInt32(); if (p>=0 && p<(int)str.length()) c->setReturnVar(c->newScriptVar(str.substr(p, 1))); else c->setReturnVar(c->newScriptVar("")); }
static void scStringLocaleCompare(const CFunctionsScopePtr &c, void *userdata) { string str = this2string(c); string compareString = c->getArgument("compareString")->toString(); int32_t val = 0; if(str<compareString) val = -1; else if(str>compareString) val = 1; c->setReturnVar(c->newScriptVar(val)); }
static void scStringCharCodeAt(const CFunctionsScopePtr &c, void *) { string str = this2string(c); int p = c->getArgument("pos")->toNumber().toInt32(); if (p>=0 && p<(int)str.length()) c->setReturnVar(c->newScriptVar((unsigned char)str.at(p))); else c->setReturnVar(c->constScriptVar(NaN)); }
static void scStringReplace(const CFunctionsScopePtr &c, void *) { const string str = this2string(c); CScriptVarPtr newsubstrVar = c->getArgument("newsubstr"); string substr, ret_str; bool global, ignoreCase, sticky; bool isRegExp = getRegExpData(c, "substr", false, "flags", substr, global, ignoreCase, sticky); if(isRegExp && !newsubstrVar->isFunction()) { #ifndef NO_REGEXP regex::flag_type flags = regex_constants::ECMAScript; if(ignoreCase) flags |= regex_constants::icase; regex_constants::match_flag_type mflags = regex_constants::match_default; if(!global) mflags |= regex_constants::format_first_only; if(sticky) mflags |= regex_constants::match_continuous; ret_str = regex_replace(str, regex(substr, flags), newsubstrVar->toString(), mflags); #endif /* NO_REGEXP */ } else { bool (*search)(const string &, const string::const_iterator &, const string &, bool, bool, string::const_iterator &, string::const_iterator &); #ifndef NO_REGEXP if(isRegExp) search = regex_search; else #endif /* NO_REGEXP */ search = string_search; string newsubstr; vector<CScriptVarPtr> arguments; if(!newsubstrVar->isFunction()) newsubstr = newsubstrVar->toString(); global = global && substr.length(); string::const_iterator search_begin=str.begin(), match_begin, match_end; if(search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)) { do { ret_str.append(search_begin, match_begin); if(newsubstrVar->isFunction()) { arguments.push_back(c->newScriptVar(string(match_begin, match_end))); newsubstr = c->getContext()->callFunction(newsubstrVar, arguments)->toString(); arguments.pop_back(); } ret_str.append(newsubstr); #if 1 /* Fix from "vcmpeq" (see Issue 14) currently untested */ if (match_begin == match_end) { if (search_begin != str.end()) ++search_begin; else break; } else { search_begin = match_end; } #else search_begin = match_end; #endif } while(global && search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)); } ret_str.append(search_begin, str.end()); } c->setReturnVar(c->newScriptVar(ret_str)); }
static void scStringSubstr(const CFunctionsScopePtr &c, void *userdata) { string str = c->getArgument("this")->getString(); int length = c->getArgumentsLength()-(int)userdata; int start = c->getArgument("start")->getInt(); if(start<0 || start>=(int)str.size()) c->setReturnVar(c->newScriptVar("")); else if(length>1) { int length = c->getArgument("length")->getInt(); c->setReturnVar(c->newScriptVar(str.substr(start, length))); } else c->setReturnVar(c->newScriptVar(str.substr(start))); }
static void scArrayJoin(const CFunctionsScopePtr &c, void *data) { string sep = c->getArgument("separator")->toString(); CScriptVarPtr arr = c->getArgument("this"); ostringstream sstr; int l = arr->getArrayLength(); for (int i=0;i<l;i++) { if (i>0) sstr << sep; sstr << arr->getArrayIndex(i)->toString(); } c->setReturnVar(c->newScriptVar(sstr.str())); }
static void scArraySort(const CFunctionsScopePtr &c, void *data) { CScriptVarPtr arr = c->getArgument("this"); CScriptVarFunctionPtr cmp_fnc; uint32_t len = arr->getLength(); if(len > 1) { int args = c->getArgumentsLength(); if(args) { cmp_fnc = c->getArgument(0); if(!cmp_fnc) c->throwError(TypeError, "invalid Array.prototype.sort argument"); } SCRIPTVAR_CHILDS_it begin = lower_bound(arr->Childs.begin(), arr->Childs.end(), "0"); /* in ECMAScript the sort algorithm is not specified * in some cases sort throws a TypeError e.G. an array element is read-only, non-configurable, getter or setter * this will result in a partially sorted array * in worst case the sort algorithm results in an endless loop (more getters with constant return value) * * 42TinyJS checks before sort if an element read-only, setter or getter and throws immediately a TypeError */ for(SCRIPTVAR_CHILDS_it it = begin; it != arr->Childs.end(); ++it) { if(!(*it)->isWritable()) c->throwError(TypeError, "property "+(*it)->getName()+" is read-only"); if(!(*it)->isConfigurable()) c->throwError(TypeError, "property "+(*it)->getName()+" is non-configurable"); if(!(*it)->getVarPtr()->isAccessor()) c->throwError(TypeError, "property "+(*it)->getName()+" is a getter and/or a setter"); } sort(begin, arr->Childs.end(), ::cmp_fnc(c, cmp_fnc)); uint32_t idx = 0; for(SCRIPTVAR_CHILDS_it it=begin; it != arr->Childs.end(); ++it, ++idx) (*it)->reName(int2string(idx)); sort(begin, arr->Childs.end(), cmp_by_name); } c->setReturnVar(arr); }
static void scStringTrim(const CFunctionsScopePtr &c, void *userdata) { string str = this2string(c); string::size_type start = 0; string::size_type end = string::npos; if(((ptr2int32(userdata)) & 2) == 0) { start = str.find_first_not_of(" \t\r\n"); if(start == string::npos) start = 0; } if(((ptr2int32(userdata)) & 1) == 0) { end = str.find_last_not_of(" \t\r\n"); if(end != string::npos) end = 1+end-start; } c->setReturnVar(c->newScriptVar(str.substr(start, end))); }
static void scArrayRemove(const CFunctionsScopePtr &c, void *data) { CScriptVarPtr obj = c->getArgument("obj"); CScriptVarPtr arr = c->getArgument("this"); uint32_t l = arr->getLength(); uint32_t offset = 0; for(SCRIPTVAR_CHILDS_it it= lower_bound(arr->Childs.begin(), arr->Childs.end(), "0"); it != arr->Childs.end(); ++it) { while(it != arr->Childs.end() && obj->mathsOp(it->getter(), LEX_EQUAL)->toBoolean()) { it = arr->Childs.erase(it); offset++; } if(offset && it != arr->Childs.end()) (*it)->reName(int2string((uint32_t)strtoul((*it)->getName().c_str(), 0, 10)-offset) ); } }
static void scStringSubstr(const CFunctionsScopePtr &c, void *userdata) { string str = this2string(c); int32_t length = c->getArgumentsLength()-ptr2int32(userdata); int32_t start = c->getArgument("start")->toNumber().toInt32(); if(start<0 || start>=(int)str.size()) c->setReturnVar(c->newScriptVar("")); else if(length>1) { int length = c->getArgument("length")->toNumber().toInt32(); c->setReturnVar(c->newScriptVar(str.substr(start, length))); } else c->setReturnVar(c->newScriptVar(str.substr(start))); }
static void scStringSearch(const CFunctionsScopePtr &c, void *userdata) { string str = this2string(c); string substr; bool global, ignoreCase, sticky; getRegExpData(c, "regexp", true, "flags", substr, global, ignoreCase, sticky); string::const_iterator search_begin=str.begin(), match_begin, match_end; #ifndef NO_REGEXP try { c->setReturnVar(c->newScriptVar(regex_search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)?match_begin-search_begin:-1)); } catch(regex_error e) { c->throwError(SyntaxError, string(e.what())+" - "+CScriptVarRegExp::ErrorStr(e.code())); } #else /* NO_REGEXP */ c->setReturnVar(c->newScriptVar(string_search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)?match_begin-search_begin:-1)); #endif /* NO_REGEXP */ }
/* static void scIntegerValueOf(const CFunctionsScopePtr &c, void *) { string str = c->getArgument("str")->toString(); int val = 0; if (str.length()==1) val = str.operator[](0); c->setReturnVar(c->newScriptVar(val)); } */ static void scJSONStringify(const CFunctionsScopePtr &c, void *) { uint32_t UniqueID = c->getContext()->allocUniqueID(); bool hasRecursion=false; c->setReturnVar(c->newScriptVar(c->getArgument("obj")->getParsableString("", " ", UniqueID, hasRecursion))); c->getContext()->freeUniqueID(); if(hasRecursion) c->throwError(TypeError, "cyclic object value"); }
static void scStringCharCodeAt(const CFunctionsScopePtr &c, void *) { string str = c->getArgument("this")->getString(); int p = c->getArgument("pos")->getInt(); if (p>=0 && p<(int)str.length()) c->setReturnVar(c->newScriptVar(str.at(p))); else c->setReturnVar(c->newScriptVar(0)); }
static void scArrayPop(const CFunctionsScopePtr &c, void *data) { CScriptVarPtr arr = c->getArgument("this"); uint32_t len = c->getLength(arr); if(len) { c->setReturnVar(c->getPropertyValue(arr, len-1)); arr->removeChild(int2string(len-1)); } else c->setReturnVar(c->constScriptVar(Undefined)); }
static void scStringSlice(const CFunctionsScopePtr &c, void *userdata) { string str = this2string(c); int32_t length = c->getArgumentsLength()-(ptr2int32(userdata) & 1); bool slice = (ptr2int32(userdata) & 2) == 0; int32_t start = c->getArgument("start")->toNumber().toInt32(); int32_t end = (int32_t)str.size(); if(slice && start<0) start = (int32_t)(str.size())+start; if(length>1) { end = c->getArgument("end")->toNumber().toInt32(); if(slice && end<0) end = (int32_t)(str.size())+end; } if(!slice && end < start) { end^=start; start^=end; end^=start; } if(start<0) start = 0; if(start>=(int)str.size()) c->setReturnVar(c->newScriptVar("")); else if(end <= start) c->setReturnVar(c->newScriptVar("")); else c->setReturnVar(c->newScriptVar(str.substr(start, end-start))); }
static void scArrayFill(const CFunctionsScopePtr &c, void *data) { CScriptVarPtr arr = c->getArgument("this"); uint32_t len = c->getLength(arr); CNumber startNumber=0, endNumber=len; CScriptVarPtr value = c->getArgument(0); CScriptVarPtr startVar = c->getArgument(1); CScriptVarPtr endVar = c->getArgument(2); c->setReturnVar(arr); if(!startVar->isUndefined()) startNumber = startVar->toNumber(); if(!endVar->isUndefined()) endNumber = endVar->toNumber(); uint32_t start = (startNumber.sign()<0 ? startNumber+len : startNumber).clamp(0, len).toUInt32(); uint32_t end = (endNumber.sign()<0 ? endNumber+len : endNumber).clamp(0, len).toUInt32(); for(; start < end; ++start) c->setProperty(arr, start, value); }
static void scArrayContains(const CFunctionsScopePtr &c, void *data) { CScriptVarPtr obj = c->getArgument("obj"); CScriptVarPtr arr = c->getArgument("this"); int l = arr->getArrayLength(); CScriptVarPtr equal = c->constScriptVar(Undefined); for (int i=0;i<l;i++) { equal = obj->mathsOp(arr->getArrayIndex(i), LEX_EQUAL); if(equal->toBoolean()) { c->setReturnVar(c->constScriptVar(true)); return; } } c->setReturnVar(c->constScriptVar(false)); }
static void scStringIndexOf(const CFunctionsScopePtr &c, void *userdata) { string str = this2string(c); string search = c->getArgument("search")->toString(); CNumber pos_n = c->getArgument("pos")->toNumber(); string::size_type pos; pos = (userdata) ? string::npos : 0; if(pos_n.sign()<0) pos = 0; else if(pos_n.isInfinity()) pos = string::npos; else if(pos_n.isFinite()) pos = pos_n.toInt32(); string::size_type p = (userdata==0) ? str.find(search, pos) : str.rfind(search, pos); if(p==string::npos) c->setReturnVar(c->newScriptVar(-1)); else c->setReturnVar(c->newScriptVar(p)); }
static void scStringSplit(const CFunctionsScopePtr &c, void *) { string str = c->getArgument("this")->getString(); CScriptVarPtr sep_var = c->getArgument("separator"); CScriptVarPtr limit_var = c->getArgument("limit"); int limit = limit_var->isUndefined() ? 0x7fffffff : limit_var->getInt(); CScriptVarPtr result(newScriptVar(c->getContext(), Array)); c->setReturnVar(result); if(limit == 0 || !str.size()) return; else if(sep_var->isUndefined()) { result->setArrayIndex(0, c->newScriptVar(str)); return; } string sep = sep_var->getString(); if(sep.size() == 0) { for(int i=0; i<min((int)sep.size(), limit); ++i) result->setArrayIndex(i, c->newScriptVar(str.substr(i,1))); return; } int length = 0; string::size_type pos = 0, last_pos=0; do { pos = str.find(sep, last_pos); result->setArrayIndex(length++, c->newScriptVar(str.substr(last_pos ,pos-last_pos))); if(length == limit || pos == string::npos) break; last_pos = pos+sep.size(); } while (last_pos < str.size()); }