X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/b5422865f473faf3977f31b96a635c4c8c4ede09..9dae56ea45a0f5f8136a5c93d6f3a7f99399ca73:/kjs/function.cpp diff --git a/kjs/function.cpp b/kjs/function.cpp deleted file mode 100644 index 92b3446..0000000 --- a/kjs/function.cpp +++ /dev/null @@ -1,877 +0,0 @@ -// -*- c-basic-offset: 2 -*- -/* - * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) - * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. - * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) - * Copyright (C) 2007 Maks Orlovich - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "function.h" - -#include "Activation.h" -#include "ExecState.h" -#include "JSGlobalObject.h" -#include "Parser.h" -#include "PropertyNameArray.h" -#include "debugger.h" -#include "dtoa.h" -#include "function_object.h" -#include "internal.h" -#include "lexer.h" -#include "nodes.h" -#include "operations.h" -#include "scope_chain_mark.h" -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace WTF; -using namespace Unicode; - -namespace KJS { - -// ----------------------------- FunctionImp ---------------------------------- - -const ClassInfo FunctionImp::info = { "Function", &InternalFunctionImp::info, 0 }; - -FunctionImp::FunctionImp(ExecState* exec, const Identifier& name, FunctionBodyNode* b, const ScopeChain& sc) - : InternalFunctionImp(exec->lexicalGlobalObject()->functionPrototype(), name) - , body(b) - , _scope(sc) -{ -} - -void FunctionImp::mark() -{ - InternalFunctionImp::mark(); - _scope.mark(); -} - -JSValue* FunctionImp::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args) -{ - FunctionExecState newExec(exec->dynamicGlobalObject(), thisObj, body.get(), exec, this, args); - JSValue* result = body->execute(&newExec); - if (newExec.completionType() == Throw) { - exec->setException(result); - return result; - } - if (newExec.completionType() == ReturnValue) - return result; - return jsUndefined(); -} - -JSValue* FunctionImp::argumentsGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot) -{ - FunctionImp* thisObj = static_cast(slot.slotBase()); - - for (ExecState* e = exec; e; e = e->callingExecState()) - if (e->function() == thisObj) { - e->dynamicGlobalObject()->tearOffActivation(e, e != exec); - return e->activationObject()->get(exec, propertyName); - } - - return jsNull(); -} - -JSValue* FunctionImp::callerGetter(ExecState* exec, JSObject*, const Identifier&, const PropertySlot& slot) -{ - FunctionImp* thisObj = static_cast(slot.slotBase()); - ExecState* e = exec; - while (e) { - if (e->function() == thisObj) - break; - e = e->callingExecState(); - } - - if (!e) - return jsNull(); - - ExecState* callingExecState = e->callingExecState(); - if (!callingExecState) - return jsNull(); - - FunctionImp* callingFunction = callingExecState->function(); - if (!callingFunction) - return jsNull(); - - return callingFunction; -} - -JSValue* FunctionImp::lengthGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot) -{ - FunctionImp* thisObj = static_cast(slot.slotBase()); - return jsNumber(thisObj->body->parameters().size()); -} - -bool FunctionImp::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) -{ - // Find the arguments from the closest context. - if (propertyName == exec->propertyNames().arguments) { - slot.setCustom(this, argumentsGetter); - return true; - } - - // Compute length of parameters. - if (propertyName == exec->propertyNames().length) { - slot.setCustom(this, lengthGetter); - return true; - } - - if (propertyName == exec->propertyNames().caller) { - slot.setCustom(this, callerGetter); - return true; - } - - return InternalFunctionImp::getOwnPropertySlot(exec, propertyName, slot); -} - -void FunctionImp::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr) -{ - if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length) - return; - InternalFunctionImp::put(exec, propertyName, value, attr); -} - -bool FunctionImp::deleteProperty(ExecState* exec, const Identifier& propertyName) -{ - if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length) - return false; - return InternalFunctionImp::deleteProperty(exec, propertyName); -} - -/* Returns the parameter name corresponding to the given index. eg: - * function f1(x, y, z): getParameterName(0) --> x - * - * If a name appears more than once, only the last index at which - * it appears associates with it. eg: - * function f2(x, x): getParameterName(0) --> null - */ -Identifier FunctionImp::getParameterName(int index) -{ - Vector& parameters = body->parameters(); - - if (static_cast(index) >= body->parameters().size()) - return CommonIdentifiers::shared()->nullIdentifier; - - Identifier name = parameters[index]; - - // Are there any subsequent parameters with the same name? - size_t size = parameters.size(); - for (size_t i = index + 1; i < size; ++i) - if (parameters[i] == name) - return CommonIdentifiers::shared()->nullIdentifier; - - return name; -} - -// ECMA 13.2.2 [[Construct]] -JSObject* FunctionImp::construct(ExecState* exec, const List& args) -{ - JSObject* proto; - JSValue* p = get(exec, exec->propertyNames().prototype); - if (p->isObject()) - proto = static_cast(p); - else - proto = exec->lexicalGlobalObject()->objectPrototype(); - - JSObject* obj(new JSObject(proto)); - - JSValue* res = call(exec,obj,args); - - if (res->isObject()) - return static_cast(res); - else - return obj; -} - -// ------------------------------ IndexToNameMap --------------------------------- - -// We map indexes in the arguments array to their corresponding argument names. -// Example: function f(x, y, z): arguments[0] = x, so we map 0 to Identifier("x"). - -// Once we have an argument name, we can get and set the argument's value in the -// activation object. - -// We use Identifier::null to indicate that a given argument's value -// isn't stored in the activation object. - -IndexToNameMap::IndexToNameMap(FunctionImp* func, const List& args) -{ - _map = new Identifier[args.size()]; - this->size = args.size(); - - unsigned i = 0; - List::const_iterator end = args.end(); - for (List::const_iterator it = args.begin(); it != end; ++i, ++it) - _map[i] = func->getParameterName(i); // null if there is no corresponding parameter -} - -IndexToNameMap::~IndexToNameMap() -{ - delete [] _map; -} - -bool IndexToNameMap::isMapped(const Identifier& index) const -{ - bool indexIsNumber; - unsigned indexAsNumber = index.toStrictUInt32(&indexIsNumber); - - if (!indexIsNumber) - return false; - - if (indexAsNumber >= size) - return false; - - if (_map[indexAsNumber].isNull()) - return false; - - return true; -} - -void IndexToNameMap::unMap(const Identifier& index) -{ - bool indexIsNumber; - unsigned indexAsNumber = index.toStrictUInt32(&indexIsNumber); - - ASSERT(indexIsNumber && indexAsNumber < size); - - _map[indexAsNumber] = CommonIdentifiers::shared()->nullIdentifier; -} - -Identifier& IndexToNameMap::operator[](const Identifier& index) -{ - bool indexIsNumber; - unsigned indexAsNumber = index.toStrictUInt32(&indexIsNumber); - - ASSERT(indexIsNumber && indexAsNumber < size); - - return _map[indexAsNumber]; -} - -// ------------------------------ Arguments --------------------------------- - -const ClassInfo Arguments::info = { "Arguments", 0, 0 }; - -// ECMA 10.1.8 -Arguments::Arguments(ExecState* exec, FunctionImp* func, const List& args, ActivationImp* act) - : JSObject(exec->lexicalGlobalObject()->objectPrototype()) - , _activationObject(act) - , indexToNameMap(func, args) -{ - putDirect(exec->propertyNames().callee, func, DontEnum); - putDirect(exec->propertyNames().length, args.size(), DontEnum); - - int i = 0; - List::const_iterator end = args.end(); - for (List::const_iterator it = args.begin(); it != end; ++it, ++i) { - Identifier name = Identifier::from(i); - if (!indexToNameMap.isMapped(name)) - putDirect(name, *it, DontEnum); - } -} - -void Arguments::mark() -{ - JSObject::mark(); - if (_activationObject && !_activationObject->marked()) - _activationObject->mark(); -} - -JSValue* Arguments::mappedIndexGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot) -{ - Arguments* thisObj = static_cast(slot.slotBase()); - return thisObj->_activationObject->get(exec, thisObj->indexToNameMap[propertyName]); -} - -bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) -{ - if (indexToNameMap.isMapped(propertyName)) { - slot.setCustom(this, mappedIndexGetter); - return true; - } - - return JSObject::getOwnPropertySlot(exec, propertyName, slot); -} - -void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr) -{ - if (indexToNameMap.isMapped(propertyName)) { - _activationObject->put(exec, indexToNameMap[propertyName], value, attr); - } else { - JSObject::put(exec, propertyName, value, attr); - } -} - -bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName) -{ - if (indexToNameMap.isMapped(propertyName)) { - indexToNameMap.unMap(propertyName); - return true; - } else { - return JSObject::deleteProperty(exec, propertyName); - } -} - -// ------------------------------ ActivationImp -------------------------------- - -const ClassInfo ActivationImp::info = { "Activation", 0, 0 }; - -ActivationImp::ActivationImp(const ActivationData& oldData, bool leaveRelic) -{ - JSVariableObject::d = new ActivationData(oldData); - d()->leftRelic = leaveRelic; -} - -ActivationImp::~ActivationImp() -{ - if (!d()->isOnStack) - delete d(); -} - -void ActivationImp::init(ExecState* exec) -{ - d()->symbolTable = &exec->function()->body->symbolTable(); - d()->exec = exec; - d()->function = exec->function(); - d()->argumentsObject = 0; -} - -JSValue* ActivationImp::argumentsGetter(ExecState* exec, JSObject*, const Identifier&, const PropertySlot& slot) -{ - ActivationImp* thisObj = static_cast(slot.slotBase()); - - if (!thisObj->d()->argumentsObject) - thisObj->createArgumentsObject(exec); - - return thisObj->d()->argumentsObject; -} - -PropertySlot::GetValueFunc ActivationImp::getArgumentsGetter() -{ - return ActivationImp::argumentsGetter; -} - -bool ActivationImp::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) -{ - if (symbolTableGet(propertyName, slot)) - return true; - - if (JSValue** location = getDirectLocation(propertyName)) { - slot.setValueSlot(this, location); - return true; - } - - // Only return the built-in arguments object if it wasn't overridden above. - if (propertyName == exec->propertyNames().arguments) { - for (ExecState* e = exec; e; e = e->callingExecState()) - if (e->function() == d()->function) { - e->dynamicGlobalObject()->tearOffActivation(e, e != exec); - ActivationImp* newActivation = e->activationObject(); - slot.setCustom(newActivation, newActivation->getArgumentsGetter()); - return true; - } - - slot.setCustom(this, getArgumentsGetter()); - return true; - } - - // We don't call through to JSObject because there's no way to give an - // activation object getter properties or a prototype. - ASSERT(!_prop.hasGetterSetterProperties()); - ASSERT(prototype() == jsNull()); - return false; -} - -bool ActivationImp::deleteProperty(ExecState* exec, const Identifier& propertyName) -{ - if (propertyName == exec->propertyNames().arguments) - return false; - - return JSVariableObject::deleteProperty(exec, propertyName); -} - -void ActivationImp::put(ExecState*, const Identifier& propertyName, JSValue* value, int attr) -{ - // If any bits other than DontDelete are set, then we bypass the read-only check. - bool checkReadOnly = !(attr & ~DontDelete); - if (symbolTablePut(propertyName, value, checkReadOnly)) - return; - - // We don't call through to JSObject because __proto__ and getter/setter - // properties are non-standard extensions that other implementations do not - // expose in the activation object. - ASSERT(!_prop.hasGetterSetterProperties()); - _prop.put(propertyName, value, attr, checkReadOnly); -} - -void ActivationImp::markChildren() -{ - LocalStorage& localStorage = d()->localStorage; - size_t size = localStorage.size(); - - for (size_t i = 0; i < size; ++i) { - JSValue* value = localStorage[i].value; - - if (!value->marked()) - value->mark(); - } - - if (!d()->function->marked()) - d()->function->mark(); - - if (d()->argumentsObject && !d()->argumentsObject->marked()) - d()->argumentsObject->mark(); -} - -void ActivationImp::mark() -{ - JSObject::mark(); - markChildren(); -} - -void ActivationImp::createArgumentsObject(ExecState* exec) -{ - // Since "arguments" is only accessible while a function is being called, - // we can retrieve our argument list from the ExecState for our function - // call instead of storing the list ourselves. - d()->argumentsObject = new Arguments(exec, d()->exec->function(), *d()->exec->arguments(), this); -} - -ActivationImp::ActivationData::ActivationData(const ActivationData& old) - : JSVariableObjectData(old) - , exec(old.exec) - , function(old.function) - , argumentsObject(old.argumentsObject) - , isOnStack(false) -{ -} - -// ------------------------------ Global Functions ----------------------------------- - -static JSValue* encode(ExecState* exec, const List& args, const char* do_not_escape) -{ - UString r = "", s, str = args[0]->toString(exec); - CString cstr = str.UTF8String(true); - if (!cstr.c_str()) - return throwError(exec, URIError, "String contained an illegal UTF-16 sequence."); - const char* p = cstr.c_str(); - for (size_t k = 0; k < cstr.size(); k++, p++) { - char c = *p; - if (c && strchr(do_not_escape, c)) { - r.append(c); - } else { - char tmp[4]; - snprintf(tmp, sizeof(tmp), "%%%02X", (unsigned char)c); - r += tmp; - } - } - return jsString(r); -} - -static JSValue* decode(ExecState* exec, const List& args, const char* do_not_unescape, bool strict) -{ - UString s = "", str = args[0]->toString(exec); - int k = 0, len = str.size(); - const UChar* d = str.data(); - UChar u; - while (k < len) { - const UChar* p = d + k; - UChar c = *p; - if (c == '%') { - int charLen = 0; - if (k <= len - 3 && isASCIIHexDigit(p[1].uc) && isASCIIHexDigit(p[2].uc)) { - const char b0 = Lexer::convertHex(p[1].uc, p[2].uc); - const int sequenceLen = UTF8SequenceLength(b0); - if (sequenceLen != 0 && k <= len - sequenceLen * 3) { - charLen = sequenceLen * 3; - char sequence[5]; - sequence[0] = b0; - for (int i = 1; i < sequenceLen; ++i) { - const UChar* q = p + i * 3; - if (q[0] == '%' && isASCIIHexDigit(q[1].uc) && isASCIIHexDigit(q[2].uc)) - sequence[i] = Lexer::convertHex(q[1].uc, q[2].uc); - else { - charLen = 0; - break; - } - } - if (charLen != 0) { - sequence[sequenceLen] = 0; - const int character = decodeUTF8Sequence(sequence); - if (character < 0 || character >= 0x110000) { - charLen = 0; - } else if (character >= 0x10000) { - // Convert to surrogate pair. - s.append(static_cast(0xD800 | ((character - 0x10000) >> 10))); - u = static_cast(0xDC00 | ((character - 0x10000) & 0x3FF)); - } else { - u = static_cast(character); - } - } - } - } - if (charLen == 0) { - if (strict) - return throwError(exec, URIError); - // The only case where we don't use "strict" mode is the "unescape" function. - // For that, it's good to support the wonky "%u" syntax for compatibility with WinIE. - if (k <= len - 6 && p[1] == 'u' - && isASCIIHexDigit(p[2].uc) && isASCIIHexDigit(p[3].uc) - && isASCIIHexDigit(p[4].uc) && isASCIIHexDigit(p[5].uc)) { - charLen = 6; - u = Lexer::convertUnicode(p[2].uc, p[3].uc, p[4].uc, p[5].uc); - } - } - if (charLen && (u.uc == 0 || u.uc >= 128 || !strchr(do_not_unescape, u.low()))) { - c = u; - k += charLen - 1; - } - } - k++; - s.append(c); - } - return jsString(s); -} - -static bool isStrWhiteSpace(unsigned short c) -{ - switch (c) { - case 0x0009: - case 0x000A: - case 0x000B: - case 0x000C: - case 0x000D: - case 0x0020: - case 0x00A0: - case 0x2028: - case 0x2029: - return true; - default: - return isSeparatorSpace(c); - } -} - -static int parseDigit(unsigned short c, int radix) -{ - int digit = -1; - - if (c >= '0' && c <= '9') { - digit = c - '0'; - } else if (c >= 'A' && c <= 'Z') { - digit = c - 'A' + 10; - } else if (c >= 'a' && c <= 'z') { - digit = c - 'a' + 10; - } - - if (digit >= radix) - return -1; - return digit; -} - -double parseIntOverflow(const char* s, int length, int radix) -{ - double number = 0.0; - double radixMultiplier = 1.0; - - for (const char* p = s + length - 1; p >= s; p--) { - if (radixMultiplier == Inf) { - if (*p != '0') { - number = Inf; - break; - } - } else { - int digit = parseDigit(*p, radix); - number += digit * radixMultiplier; - } - - radixMultiplier *= radix; - } - - return number; -} - -static double parseInt(const UString& s, int radix) -{ - int length = s.size(); - int p = 0; - - while (p < length && isStrWhiteSpace(s[p].uc)) { - ++p; - } - - double sign = 1; - if (p < length) { - if (s[p] == '+') { - ++p; - } else if (s[p] == '-') { - sign = -1; - ++p; - } - } - - if ((radix == 0 || radix == 16) && length - p >= 2 && s[p] == '0' && (s[p + 1] == 'x' || s[p + 1] == 'X')) { - radix = 16; - p += 2; - } else if (radix == 0) { - if (p < length && s[p] == '0') - radix = 8; - else - radix = 10; - } - - if (radix < 2 || radix > 36) - return NaN; - - int firstDigitPosition = p; - bool sawDigit = false; - double number = 0; - while (p < length) { - int digit = parseDigit(s[p].uc, radix); - if (digit == -1) - break; - sawDigit = true; - number *= radix; - number += digit; - ++p; - } - - if (number >= mantissaOverflowLowerBound) { - if (radix == 10) - number = kjs_strtod(s.substr(firstDigitPosition, p - firstDigitPosition).ascii(), 0); - else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32) - number = parseIntOverflow(s.substr(firstDigitPosition, p - firstDigitPosition).ascii(), p - firstDigitPosition, radix); - } - - if (!sawDigit) - return NaN; - - return sign * number; -} - -static double parseFloat(const UString& s) -{ - // Check for 0x prefix here, because toDouble allows it, but we must treat it as 0. - // Need to skip any whitespace and then one + or - sign. - int length = s.size(); - int p = 0; - while (p < length && isStrWhiteSpace(s[p].uc)) { - ++p; - } - if (p < length && (s[p] == '+' || s[p] == '-')) { - ++p; - } - if (length - p >= 2 && s[p] == '0' && (s[p + 1] == 'x' || s[p + 1] == 'X')) { - return 0; - } - - return s.toDouble( true /*tolerant*/, false /* NaN for empty string */ ); -} - -JSValue* globalFuncEval(ExecState* exec, JSObject* thisObj, const List& args) -{ - JSValue* x = args[0]; - if (!x->isString()) - return x; - - UString s = x->toString(exec); - - int errLine; - UString errMsg; - - SourceCode source = makeSource(s); - RefPtr evalNode = parser().parse(source, &errLine, &errMsg); - - // debugger code removed - - // No program node means a syntax occurred - if (!evalNode) - return throwError(exec, SyntaxError, errMsg, errLine, source.provider()->asID(), NULL); - - bool switchGlobal = thisObj && thisObj != exec->dynamicGlobalObject() && thisObj->isGlobalObject(); - - // enter a new execution context - exec->dynamicGlobalObject()->tearOffActivation(exec); - JSGlobalObject* globalObject = switchGlobal ? static_cast(thisObj) : exec->dynamicGlobalObject(); - EvalExecState newExec(globalObject, evalNode.get(), exec); - - if (switchGlobal) { - newExec.pushScope(thisObj); - newExec.setVariableObject(static_cast(thisObj)); - } - JSValue* value = evalNode->execute(&newExec); - if (switchGlobal) - newExec.popScope(); - - if (newExec.completionType() == Throw) { - exec->setException(value); - return value; - } - - return value ? value : jsUndefined(); -} - -JSValue* globalFuncParseInt(ExecState* exec, JSObject*, const List& args) -{ - return jsNumber(parseInt(args[0]->toString(exec), args[1]->toInt32(exec))); -} - -JSValue* globalFuncParseFloat(ExecState* exec, JSObject*, const List& args) -{ - return jsNumber(parseFloat(args[0]->toString(exec))); -} - -JSValue* globalFuncIsNaN(ExecState* exec, JSObject*, const List& args) -{ - return jsBoolean(isnan(args[0]->toNumber(exec))); -} - -JSValue* globalFuncIsFinite(ExecState* exec, JSObject*, const List& args) -{ - double n = args[0]->toNumber(exec); - return jsBoolean(!isnan(n) && !isinf(n)); -} - -JSValue* globalFuncDecodeURI(ExecState* exec, JSObject*, const List& args) -{ - static const char do_not_unescape_when_decoding_URI[] = - "#$&+,/:;=?@"; - - return decode(exec, args, do_not_unescape_when_decoding_URI, true); -} - -JSValue* globalFuncDecodeURIComponent(ExecState* exec, JSObject*, const List& args) -{ - return decode(exec, args, "", true); -} - -JSValue* globalFuncEncodeURI(ExecState* exec, JSObject*, const List& args) -{ - static const char do_not_escape_when_encoding_URI[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789" - "!#$&'()*+,-./:;=?@_~"; - - return encode(exec, args, do_not_escape_when_encoding_URI); -} - -JSValue* globalFuncEncodeURIComponent(ExecState* exec, JSObject*, const List& args) -{ - static const char do_not_escape_when_encoding_URI_component[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789" - "!'()*-._~"; - - return encode(exec, args, do_not_escape_when_encoding_URI_component); -} - -JSValue* globalFuncEscape(ExecState* exec, JSObject*, const List& args) -{ - static const char do_not_escape[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789" - "*+-./@_"; - - UString r = "", s, str = args[0]->toString(exec); - const UChar* c = str.data(); - for (int k = 0; k < str.size(); k++, c++) { - int u = c->uc; - if (u > 255) { - char tmp[7]; - snprintf(tmp, sizeof(tmp), "%%u%04X", u); - s = UString(tmp); - } else if (u != 0 && strchr(do_not_escape, (char)u)) - s = UString(c, 1); - else { - char tmp[4]; - snprintf(tmp, sizeof(tmp), "%%%02X", u); - s = UString(tmp); - } - r += s; - } - - return jsString(r); -} - -JSValue* globalFuncUnescape(ExecState* exec, JSObject*, const List& args) -{ - UString s = "", str = args[0]->toString(exec); - int k = 0, len = str.size(); - while (k < len) { - const UChar* c = str.data() + k; - UChar u; - if (*c == UChar('%') && k <= len - 6 && *(c + 1) == UChar('u')) { - if (Lexer::isHexDigit((c + 2)->uc) && Lexer::isHexDigit((c + 3)->uc) && Lexer::isHexDigit((c + 4)->uc) && Lexer::isHexDigit((c + 5)->uc)) { - u = Lexer::convertUnicode((c + 2)->uc, (c + 3)->uc, (c + 4)->uc, (c + 5)->uc); - c = &u; - k += 5; - } - } else if (*c == UChar('%') && k <= len - 3 && Lexer::isHexDigit((c + 1)->uc) && Lexer::isHexDigit((c + 2)->uc)) { - u = UChar(Lexer::convertHex((c+1)->uc, (c+2)->uc)); - c = &u; - k += 2; - } - k++; - s += UString(c, 1); - } - - return jsString(s); -} - -#ifndef NDEBUG -JSValue* globalFuncKJSPrint(ExecState* exec, JSObject*, const List& args) -{ - puts(args[0]->toString(exec).ascii()); - return jsUndefined(); -} -#endif - -// ------------------------------ PrototypeFunction ------------------------------- - -PrototypeFunction::PrototypeFunction(ExecState* exec, int len, const Identifier& name, JSMemberFunction function) - : InternalFunctionImp(exec->lexicalGlobalObject()->functionPrototype(), name) - , m_function(function) -{ - ASSERT_ARG(function, function); - putDirect(exec->propertyNames().length, jsNumber(len), DontDelete | ReadOnly | DontEnum); -} - -PrototypeFunction::PrototypeFunction(ExecState* exec, FunctionPrototype* functionPrototype, int len, const Identifier& name, JSMemberFunction function) - : InternalFunctionImp(functionPrototype, name) - , m_function(function) -{ - ASSERT_ARG(function, function); - putDirect(exec->propertyNames().length, jsNumber(len), DontDelete | ReadOnly | DontEnum); -} - -JSValue* PrototypeFunction::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args) -{ - return m_function(exec, thisObj, args); -} - -} // namespace KJS