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 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 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)"); }
//************************************ // 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 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 scStringMatch(const CFunctionsScopePtr &c, void *) { string str = this2string(c); string flags="flags", substr, newsubstr, match; bool global, ignoreCase, sticky; CScriptVarRegExpPtr RegExp = getRegExpData(c, "regexp", true, "flags", substr, global, ignoreCase, sticky); if(!global) { if(!RegExp) RegExp = ::newScriptVar(c->getContext(), substr, flags); if(RegExp) { try { c->setReturnVar(RegExp->exec(str)); } catch(regex_error e) { c->throwError(SyntaxError, string(e.what())+" - "+CScriptVarRegExp::ErrorStr(e.code())); } } } else { try { CScriptVarArrayPtr retVar = c->newScriptVar(Array); int idx=0; string::size_type offset=0; global = global && substr.length(); string::const_iterator search_begin=str.begin(), match_begin, match_end; if(regex_search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)) { do { offset = match_begin-str.begin(); retVar->addChild(int2string(idx++), c->newScriptVar(string(match_begin, match_end))); #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 && regex_search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)); } if(idx) { retVar->addChild("input", c->newScriptVar(str)); retVar->addChild("index", c->newScriptVar((int)offset)); c->setReturnVar(retVar); } else c->setReturnVar(c->constScriptVar(Null)); } catch(regex_error e) { c->throwError(SyntaxError, string(e.what())+" - "+CScriptVarRegExp::ErrorStr(e.code())); } } }
static void scStringSplit(const CFunctionsScopePtr &c, void *) { const string str = this2string(c); string seperator; bool global, ignoreCase, sticky; #ifndef NO_REGEXP CScriptVarRegExpPtr RegExp = getRegExpData(c, "separator", true, 0, seperator, global, ignoreCase, sticky); #else getRegExpData(c, "separator", true, 0, seperator, global, ignoreCase, sticky); #endif CScriptVarPtr sep_var = c->getArgument("separator"); CScriptVarPtr limit_var = c->getArgument("limit"); int limit = limit_var->isUndefined() ? 0x7fffffff : limit_var->toNumber().toInt32(); CScriptVarPtr result(c->newScriptVar(Array)); c->setReturnVar(result); if(limit == 0) return; else if(!str.size() || sep_var->isUndefined()) { result->addChild("0", c->newScriptVar(str)); return; } if(seperator.size() == 0) { for(int i=0; i<min((int)str.size(), limit); ++i) result->addChild(i, c->newScriptVar(str.substr(i,1))); return; } int length = 0; string::const_iterator search_begin=str.begin(), match_begin, match_end; #ifndef NO_REGEXP smatch match; #endif bool found=true; while(found) { #ifndef NO_REGEXP if(RegExp) { try { found = regex_search(str, search_begin, seperator, ignoreCase, sticky, match_begin, match_end, match); } catch(regex_error e) { c->throwError(SyntaxError, string(e.what())+" - "+CScriptVarRegExp::ErrorStr(e.code())); } } else /* NO_REGEXP */ #endif found = string_search(str, search_begin, seperator, ignoreCase, sticky, match_begin, match_end); string f; if(found) { result->addChild(length++, c->newScriptVar(string(search_begin, match_begin))); if(length>=limit) break; #ifndef NO_REGEXP for(uint32_t i=1; i<match.size(); i++) { if(match[i].matched) result->addChild(length++, c->newScriptVar(string(match[i].first, match[i].second))); else result->addChild(length++, c->constScriptVar(Undefined)); if(length>=limit) break; } if(length>=limit) break; #endif search_begin = match_end; } else { result->addChild(length++, c->newScriptVar(string(search_begin,str.end()))); if(length>=limit) break; } } }