1 // -*- c-basic-offset: 2 -*-
3 * This file is part of the KDE libraries
4 * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
5 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
6 * Copyright (C) 2003 Apple Computer, Inc.
7 * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
8 * Copyright (C) 2007 Maksim Orlovich (maksim@kde.org)
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
29 #include "scriptfunction.h"
32 #include "function_object.h"
35 #include "operations.h"
37 #include "PropertyNameArray.h"
44 #include "wtf/DisallowCType.h"
45 #include "wtf/ASCIICType.h"
46 #include "bytecode/machine.h"
52 // ----------------------------- FunctionImp ----------------------------------
54 const ClassInfo
FunctionImp::info
= {"Function", &InternalFunctionImp::info
, 0, 0};
56 FunctionImp::FunctionImp(ExecState
* exec
, const Identifier
& n
, FunctionBodyNode
* b
, const ScopeChain
& sc
)
57 : InternalFunctionImp(static_cast<FunctionPrototype
*>
58 (exec
->lexicalInterpreter()->builtinFunctionPrototype()), n
)
64 void FunctionImp::mark()
66 InternalFunctionImp::mark();
70 FunctionImp::~FunctionImp()
74 void FunctionImp::initialCompile(ExecState
* newExec
)
76 FunctionBodyNode
* body
= this->body
.get();
78 // Reserve various slots needed for the activation object. We do it only once,
79 // --- isCompiled() would return true even if debugging state changed
80 body
->reserveSlot(ActivationImp::LengthSlot
, false);
81 body
->reserveSlot(ActivationImp::TearOffNeeded
, false);
82 body
->reserveSlot(ActivationImp::ScopeLink
, false /* will mark via ScopeChain::mark() */);
83 body
->reserveSlot(ActivationImp::FunctionSlot
, true);
84 body
->reserveSlot(ActivationImp::ArgumentsObjectSlot
, true);
86 // Create declarations for parameters, and allocate the symbols.
87 // We always just give them sequential positions, to make passInParameters
88 // simple (though perhaps wasting memory in the trivial case)
89 for (size_t i
= 0; i
< body
->numParams(); ++i
)
90 body
->addSymbolOverwriteID(i
+ ActivationImp::NumReservedSlots
, body
->paramName(i
), DontDelete
);
92 body
->processDecls(newExec
);
93 body
->compile(FunctionCode
, newExec
->dynamicInterpreter()->debugger() ? Debug
: Release
);
96 JSValue
* FunctionImp::callAsFunction(ExecState
* exec
, JSObject
* thisObj
, const List
& args
)
100 Debugger
* dbg
= exec
->dynamicInterpreter()->debugger();
102 // enter a new execution context
103 FunctionExecState
newExec(exec
->dynamicInterpreter(), thisObj
, body
.get(), exec
, this);
104 if (exec
->hadException())
105 newExec
.setException(exec
->exception());
107 FunctionBodyNode
* body
= this->body
.get();
109 // The first time we're called, compute the set of local variables,
110 // and compile the body. (note that parameters have been collected
111 // during the AST build)
112 CompileType currentState
= body
->compileState();
113 if (currentState
== NotCompiled
) {
114 initialCompile(&newExec
);
116 // Otherwise, we may still need to recompile due to debug...
117 CompileType desiredState
= dbg
? Debug
: Release
;
118 if (desiredState
!= currentState
)
119 body
->compile(FunctionCode
, desiredState
);
122 size_t stackSize
= 0;
123 LocalStorageEntry
* stackSpace
= 0;
125 // We always allocate on stack initially, and tearoff only after we're done.
126 int regs
= body
->numLocalsAndRegisters();
127 stackSize
= sizeof(LocalStorageEntry
) * regs
;
128 stackSpace
= (LocalStorageEntry
*)exec
->dynamicInterpreter()->stackAlloc(stackSize
);
130 ActivationImp
* activation
= static_cast<ActivationImp
*>(newExec
.activationObject());
131 activation
->setup(&newExec
, this, &args
, stackSpace
);
132 activation
->tearOffNeededSlot() = body
->tearOffAtEnd();
135 bool cont
= dbg
->enterContext(&newExec
, body
->sourceId(), body
->firstLine(), this, args
);
138 return jsUndefined();
142 newExec
.initLocalStorage(stackSpace
, regs
);
144 JSValue
* result
= Machine::runBlock(&newExec
, body
->code(), exec
);
146 // If we need to tear off now --- either due to static flag above, or
147 // if execution requested it dynamically --- do so now.
148 if (activation
->tearOffNeededSlot()) {
149 activation
->performTearOff();
151 // Otherwise, we recycle the activation object; we must clear its
152 // data pointer, though, since that may become dead.
153 // (we also unlink it from the scope chain at this time)
154 activation
->scopeLink().deref();
155 activation
->localStorage
= 0;
156 exec
->dynamicInterpreter()->recycleActivation(activation
);
159 // Now free the stack space..
160 exec
->dynamicInterpreter()->stackFree(stackSize
);
163 if (exec
->exception())
164 printInfo(exec
,"throwing", exec
->exception());
166 printInfo(exec
,"returning", result
);
169 // The debugger may have been deallocated by now if the WebFrame
170 // we were running in has been destroyed, so refetch it.
171 // See http://bugs.webkit.org/show_bug.cgi?id=9477
172 dbg
= exec
->dynamicInterpreter()->debugger();
175 int cont
= dbg
->exitContext(&newExec
, body
->sourceId(), body
->lastLine(), this);
178 return jsUndefined();
185 JSValue
*FunctionImp::argumentsGetter(ExecState
* exec
, JSObject
*, const Identifier
& propertyName
, const PropertySlot
& slot
)
187 FunctionImp
*thisObj
= static_cast<FunctionImp
*>(slot
.slotBase());
188 ExecState
*context
= exec
;
190 if (context
->function() == thisObj
) {
191 return static_cast<ActivationImp
*>(context
->activationObject())->get(exec
, propertyName
);
193 context
= context
->callingExecState();
198 JSValue
*FunctionImp::callerGetter(ExecState
* exec
, JSObject
*, const Identifier
&, const PropertySlot
& slot
)
200 FunctionImp
* thisObj
= static_cast<FunctionImp
*>(slot
.slotBase());
201 ExecState
* context
= exec
;
203 if (context
->function() == thisObj
)
205 context
= context
->callingExecState();
211 ExecState
* callingContext
= context
->callingExecState();
215 FunctionImp
* callingFunction
= callingContext
->function();
216 if (!callingFunction
)
219 return callingFunction
;
222 JSValue
*FunctionImp::lengthGetter(ExecState
*, JSObject
*, const Identifier
&, const PropertySlot
& slot
)
224 FunctionImp
*thisObj
= static_cast<FunctionImp
*>(slot
.slotBase());
225 return jsNumber(thisObj
->body
->numParams());
228 JSValue
* FunctionImp::nameGetter(ExecState
*, JSObject
*, const Identifier
&, const PropertySlot
& slot
)
230 FunctionImp
* thisObj
= static_cast<FunctionImp
*>(slot
.slotBase());
231 return jsString(thisObj
->functionName().ustring());
234 bool FunctionImp::getOwnPropertySlot(ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
& slot
)
236 // Find the arguments from the closest context.
237 if (propertyName
== exec
->propertyNames().arguments
) {
238 slot
.setCustom(this, argumentsGetter
);
242 // Compute length of parameters.
243 if (propertyName
== exec
->propertyNames().length
) {
244 slot
.setCustom(this, lengthGetter
);
248 // Calling function (Mozilla-extension)
249 if (propertyName
== exec
->propertyNames().caller
) {
250 slot
.setCustom(this, callerGetter
);
254 // Function name (Mozilla-extension)
255 if (propertyName
== exec
->propertyNames().name
) {
256 slot
.setCustom(this, nameGetter
);
260 return InternalFunctionImp::getOwnPropertySlot(exec
, propertyName
, slot
);
263 void FunctionImp::put(ExecState
*exec
, const Identifier
&propertyName
, JSValue
*value
, int attr
)
265 if (propertyName
== exec
->propertyNames().arguments
||
266 propertyName
== exec
->propertyNames().length
||
267 propertyName
== exec
->propertyNames().name
)
269 InternalFunctionImp::put(exec
, propertyName
, value
, attr
);
272 bool FunctionImp::deleteProperty(ExecState
*exec
, const Identifier
&propertyName
)
274 if (propertyName
== exec
->propertyNames().arguments
||
275 propertyName
== exec
->propertyNames().length
||
276 propertyName
== exec
->propertyNames().name
)
278 return InternalFunctionImp::deleteProperty(exec
, propertyName
);
281 /* Returns the parameter name corresponding to the given index. eg:
282 * function f1(x, y, z): getParameterName(0) --> x
284 * If a name appears more than once, only the last index at which
285 * it appears associates with it. eg:
286 * function f2(x, x): getParameterName(0) --> null
288 Identifier
FunctionImp::getParameterName(int index
)
290 if (index
>= body
->numParams())
291 return CommonIdentifiers::shared()->nullIdentifier
;
293 Identifier name
= body
->paramName(index
);
295 // Are there any subsequent parameters with the same name?
296 for (int pos
= index
+ 1; pos
< body
->numParams(); ++pos
)
297 if (body
->paramName(pos
) == name
)
298 return CommonIdentifiers::shared()->nullIdentifier
;
303 bool FunctionImp::implementsConstruct() const
308 // ECMA 13.2.2 [[Construct]]
309 JSObject
*FunctionImp::construct(ExecState
*exec
, const List
&args
)
312 JSValue
*p
= get(exec
, exec
->propertyNames().prototype
);
314 proto
= static_cast<JSObject
*>(p
);
316 proto
= exec
->lexicalInterpreter()->builtinObjectPrototype();
318 JSObject
*obj(new JSObject(proto
));
320 JSValue
*res
= call(exec
,obj
,args
);
323 return static_cast<JSObject
*>(res
);
328 // ------------------------------ IndexToNameMap ---------------------------------
330 // We map indexes in the arguments array to their corresponding argument names.
331 // Example: function f(x, y, z): arguments[0] = x, so we map 0 to Identifier("x").
333 // Once we have an argument name, we can get and set the argument's value in the
334 // activation object.
336 // We use Identifier::null to indicate that a given argument's value
337 // isn't stored in the activation object.
339 IndexToNameMap::IndexToNameMap(FunctionImp
*func
, const List
&args
)
341 _map
= new Identifier
[args
.size()];
342 this->size
= args
.size();
345 ListIterator iterator
= args
.begin();
346 for (; iterator
!= args
.end(); i
++, iterator
++)
347 _map
[i
] = func
->getParameterName(i
); // null if there is no corresponding parameter
350 IndexToNameMap::~IndexToNameMap() {
354 bool IndexToNameMap::isMapped(const Identifier
&index
) const
357 int indexAsNumber
= index
.toUInt32(&indexIsNumber
);
362 if (indexAsNumber
>= size
)
365 if (_map
[indexAsNumber
].isNull())
371 void IndexToNameMap::unMap(const Identifier
&index
)
374 int indexAsNumber
= index
.toUInt32(&indexIsNumber
);
376 assert(indexIsNumber
&& indexAsNumber
< size
);
378 _map
[indexAsNumber
] = CommonIdentifiers::shared()->nullIdentifier
;;
381 Identifier
& IndexToNameMap::operator[](int index
)
386 Identifier
& IndexToNameMap::operator[](const Identifier
&index
)
389 int indexAsNumber
= index
.toUInt32(&indexIsNumber
);
391 assert(indexIsNumber
&& indexAsNumber
< size
);
393 return (*this)[indexAsNumber
];
396 // ------------------------------ Arguments ---------------------------------
398 const ClassInfo
Arguments::info
= {"Arguments", 0, 0, 0};
401 Arguments::Arguments(ExecState
*exec
, FunctionImp
*func
, const List
&args
, ActivationImp
*act
)
402 : JSObject(exec
->lexicalInterpreter()->builtinObjectPrototype()),
403 _activationObject(act
),
404 indexToNameMap(func
, args
)
406 putDirect(exec
->propertyNames().callee
, func
, DontEnum
);
407 putDirect(exec
->propertyNames().length
, args
.size(), DontEnum
);
410 ListIterator iterator
= args
.begin();
411 for (; iterator
!= args
.end(); i
++, iterator
++) {
412 if (!indexToNameMap
.isMapped(Identifier::from(i
))) {
413 JSObject::put(exec
, Identifier::from(i
), *iterator
, DontEnum
);
418 void Arguments::mark()
421 if (_activationObject
&& !_activationObject
->marked())
422 _activationObject
->mark();
425 JSValue
*Arguments::mappedIndexGetter(ExecState
* exec
, JSObject
*, const Identifier
& propertyName
, const PropertySlot
& slot
)
427 Arguments
*thisObj
= static_cast<Arguments
*>(slot
.slotBase());
428 return thisObj
->_activationObject
->get(exec
, thisObj
->indexToNameMap
[propertyName
]);
431 bool Arguments::getOwnPropertySlot(ExecState
*exec
, const Identifier
& propertyName
, PropertySlot
& slot
)
433 if (indexToNameMap
.isMapped(propertyName
)) {
434 slot
.setCustom(this, mappedIndexGetter
);
438 return JSObject::getOwnPropertySlot(exec
, propertyName
, slot
);
441 void Arguments::put(ExecState
*exec
, const Identifier
&propertyName
, JSValue
*value
, int attr
)
443 if (indexToNameMap
.isMapped(propertyName
)) {
444 _activationObject
->put(exec
, indexToNameMap
[propertyName
], value
, attr
);
446 JSObject::put(exec
, propertyName
, value
, attr
);
450 bool Arguments::deleteProperty(ExecState
*exec
, const Identifier
&propertyName
)
452 if (indexToNameMap
.isMapped(propertyName
)) {
453 indexToNameMap
.unMap(propertyName
);
456 return JSObject::deleteProperty(exec
, propertyName
);
460 // ------------------------------ ActivationImp --------------------------------
462 const ClassInfo
ActivationImp::info
= {"Activation", 0, 0, 0};
465 void ActivationImp::setup(ExecState
* exec
, FunctionImp
*function
,
466 const List
* arguments
, LocalStorageEntry
* entries
)
468 FunctionBodyNode
* body
= function
->body
.get();
470 size_t total
= body
->numLocalsAndRegisters();
471 localStorage
= entries
;
472 lengthSlot() = total
;
474 // we can now link ourselves into the scope, which will also fix up our scopeLink().
475 exec
->pushVariableObjectScope(this);
477 const FunctionBodyNode::SymbolInfo
* symInfo
= body
->getLocalInfo();
480 this->arguments
= arguments
;
481 functionSlot() = function
;
482 argumentsObjectSlot() = jsUndefined();
483 symbolTable
= &body
->symbolTable();
485 // Set the mark/don't mark flags and attributes for everything
486 for (size_t p
= 0; p
< total
; ++p
)
487 entries
[p
].attributes
= symInfo
[p
].attr
;
489 // Pass in the parameters (ECMA 10.1.3q)
491 fprintf(stderr
, "---------------------------------------------------\n"
492 "processing parameters for %s call\n",
493 function
->functionName().isEmpty() ? "(internal)" : function
->functionName().ascii());
495 size_t numParams
= body
->numParams();
496 for (size_t pos
= 0; pos
< numParams
; ++pos
) {
497 size_t symNum
= pos
+ ActivationImp::NumReservedSlots
;
498 JSValue
* v
= (*arguments
)[pos
];
500 entries
[symNum
].val
.valueVal
= v
;
503 fprintf(stderr
, "setting parameter %s", body
->paramName(pos
).ascii());
504 printInfo(exec
, "to", v
);
508 // Initialize the rest of the locals to 'undefined'
509 for (size_t pos
= numParams
+ ActivationImp::NumReservedSlots
; pos
< total
; ++pos
)
510 entries
[pos
].val
.valueVal
= jsUndefined();
512 // Finally, put in the functions. Note that this relies on above
513 // steps to have completed, since it can trigger a GC.
514 size_t numFuns
= body
->numFunctionLocals();
515 size_t* funsData
= body
->getFunctionLocalInfo();
516 for (size_t fun
= 0; fun
< numFuns
; ++fun
) {
517 size_t id
= funsData
[fun
];
518 entries
[id
].val
.valueVal
= symInfo
[id
].funcDecl
->makeFunctionObject(exec
);
522 void ActivationImp::performTearOff()
524 // Create a new local array, copy stuff over
525 size_t total
= lengthSlot();
526 LocalStorageEntry
* entries
= new LocalStorageEntry
[total
];
527 std::memcpy(entries
, localStorage
, total
*sizeof(LocalStorageEntry
));
528 localStorage
= entries
;
531 void ActivationImp::requestTearOff()
533 tearOffNeededSlot() = true;
536 JSValue
*ActivationImp::argumentsGetter(ExecState
* exec
, JSObject
*, const Identifier
&, const PropertySlot
& slot
)
538 ActivationImp
* thisObj
= static_cast<ActivationImp
*>(slot
.slotBase());
540 if (thisObj
->argumentsObjectSlot() == jsUndefined())
541 thisObj
->createArgumentsObject(exec
);
543 return thisObj
->argumentsObjectSlot();
547 PropertySlot::GetValueFunc
ActivationImp::getArgumentsGetter()
549 return ActivationImp::argumentsGetter
;
552 bool ActivationImp::getOwnPropertySlot(ExecState
*exec
, const Identifier
& propertyName
, PropertySlot
& slot
)
554 if (symbolTableGet(propertyName
, slot
))
557 if (JSValue
** location
= getDirectLocation(propertyName
)) {
558 slot
.setValueSlot(this, location
);
562 // Only return the built-in arguments object if it wasn't overridden above.
563 if (propertyName
== exec
->propertyNames().arguments
) {
564 slot
.setCustom(this, getArgumentsGetter());
568 // We don't call through to JSObject because there's no way to give an
569 // activation object getter properties or a prototype.
570 ASSERT(!_prop
.hasGetterSetterProperties());
571 ASSERT(prototype() == jsNull());
575 bool ActivationImp::deleteProperty(ExecState
*exec
, const Identifier
&propertyName
)
577 if (propertyName
== exec
->propertyNames().arguments
)
580 return JSVariableObject::deleteProperty(exec
, propertyName
);
583 void ActivationImp::put(ExecState
*, const Identifier
& propertyName
, JSValue
* value
, int attr
)
585 // If any bits other than DontDelete are set, then we bypass the read-only check.
586 bool checkReadOnly
= !(attr
& ~DontDelete
);
587 if (symbolTablePut(propertyName
, value
, checkReadOnly
))
590 // We don't call through to JSObject because __proto__ and getter/setter
591 // properties are non-standard extensions that other implementations do not
592 // expose in the activation object.
593 ASSERT(!_prop
.hasGetterSetterProperties());
594 _prop
.put(propertyName
, value
, attr
, checkReadOnly
);
597 void ActivationImp::createArgumentsObject(ExecState
*exec
)
600 argumentsObjectSlot() = new Arguments(exec
, static_cast<FunctionImp
*>(functionSlot()),
601 *arguments
, const_cast<ActivationImp
*>(this));
604 // ------------------------------ GlobalFunc -----------------------------------
607 GlobalFuncImp::GlobalFuncImp(ExecState
* exec
, FunctionPrototype
* funcProto
, int i
, int len
, const Identifier
& name
)
608 : InternalFunctionImp(funcProto
, name
)
611 putDirect(exec
->propertyNames().length
, len
, DontDelete
|ReadOnly
|DontEnum
);
614 static JSValue
*encode(ExecState
*exec
, const List
&args
, const char *do_not_escape
)
616 UString r
= "", s
, str
= args
[0]->toString(exec
);
617 CString cstr
= str
.UTF8String();
618 const char *p
= cstr
.c_str();
619 for (size_t k
= 0; k
< cstr
.size(); k
++, p
++) {
621 if (c
&& strchr(do_not_escape
, c
)) {
625 sprintf(tmp
, "%%%02X", (unsigned char)c
);
632 static JSValue
*decode(ExecState
*exec
, const List
&args
, const char *do_not_unescape
)
634 UString s
= "", str
= args
[0]->toString(exec
);
635 int k
= 0, len
= str
.size();
636 const UChar
*d
= str
.data();
639 const UChar
*p
= d
+ k
;
643 if (k
<= len
- 3 && isASCIIHexDigit(p
[1].uc
) && isASCIIHexDigit(p
[2].uc
)) {
644 const char b0
= Lexer::convertHex(p
[1].uc
, p
[2].uc
);
645 const int sequenceLen
= UTF8SequenceLength(b0
);
646 if (sequenceLen
!= 0 && k
<= len
- sequenceLen
* 3) {
647 charLen
= sequenceLen
* 3;
650 for (int i
= 1; i
< sequenceLen
; ++i
) {
651 const UChar
*q
= p
+ i
* 3;
652 if (q
[0] == '%' && isASCIIHexDigit(q
[1].uc
) && isASCIIHexDigit(q
[2].uc
))
653 sequence
[i
] = Lexer::convertHex(q
[1].uc
, q
[2].uc
);
660 sequence
[sequenceLen
] = 0;
661 const int character
= decodeUTF8Sequence(sequence
);
662 if (character
< 0 || character
>= 0x110000) {
664 } else if (character
>= 0x10000) {
665 // Convert to surrogate pair.
666 s
.append(static_cast<unsigned short>(0xD800 | ((character
- 0x10000) >> 10)));
667 u
= static_cast<unsigned short>(0xDC00 | ((character
- 0x10000) & 0x3FF));
669 u
= static_cast<unsigned short>(character
);
675 return throwError(exec
, URIError
);
676 if (u
.uc
== 0 || u
.uc
>= 128 || !strchr(do_not_unescape
, u
.low())) {
687 static bool isStrWhiteSpace(unsigned short c
)
697 // Unicode category Zs
698 case 0x0020: // SPACE
699 case 0x00A0: // NO-BREAK SPACE
700 case 0x1680: // OGHAM SPACE MARK
701 case 0x180E: // MONGOLIAN VOWEL SEPARATOR
702 case 0x2000: // EN QUAD
703 case 0x2001: // EM QUAD
704 case 0x2002: // EN SPACE
705 case 0x2003: // EM SPACE
706 case 0x2004: // THREE-PER-EM SPACE
707 case 0x2005: // FOUR-PER-EM SPACE
708 case 0x2006: // SIX-PER-EM SPACE
709 case 0x2007: // FIGURE SPACE
710 case 0x2008: // PUNCTUATION SPACE
711 case 0x2009: // THIN SPACE
712 case 0x200A: // HAIR SPACE
713 case 0x202F: // NARROW NO-BREAK SPACE
714 case 0x205F: // MEDIUM MATHEMATICAL SPACE
715 case 0x3000: // IDEOGRAPHIC SPACE
722 static int parseDigit(unsigned short c
, int radix
)
726 if (c
>= '0' && c
<= '9') {
728 } else if (c
>= 'A' && c
<= 'Z') {
729 digit
= c
- 'A' + 10;
730 } else if (c
>= 'a' && c
<= 'z') {
731 digit
= c
- 'a' + 10;
739 double parseIntOverflow(const char* s
, int length
, int radix
)
742 double radixMultiplier
= 1.0;
744 for (const char* p
= s
+ length
- 1; p
>= s
; p
--) {
745 if (radixMultiplier
== Inf
) {
751 int digit
= parseDigit(*p
, radix
);
752 number
+= digit
* radixMultiplier
;
755 radixMultiplier
*= radix
;
761 static double parseInt(const UString
&s
, int radix
)
763 int length
= s
.size();
766 while (p
< length
&& isStrWhiteSpace(s
[p
].uc
)) {
774 } else if (s
[p
] == '-') {
780 if ((radix
== 0 || radix
== 16) && length
- p
>= 2 && s
[p
] == '0' && (s
[p
+ 1] == 'x' || s
[p
+ 1] == 'X')) {
783 } else if (radix
== 0) {
784 if (p
< length
&& s
[p
] == '0')
790 if (radix
< 2 || radix
> 36)
793 int firstDigitPosition
= p
;
794 bool sawDigit
= false;
797 int digit
= parseDigit(s
[p
].uc
, radix
);
806 if (number
>= mantissaOverflowLowerBound
) {
808 number
= kjs_strtod(s
.substr(firstDigitPosition
, p
- firstDigitPosition
).ascii(), 0);
809 else if (radix
== 2 || radix
== 4 || radix
== 8 || radix
== 16 || radix
== 32)
810 number
= parseIntOverflow(s
.substr(firstDigitPosition
, p
- firstDigitPosition
).ascii(), p
- firstDigitPosition
, radix
);
816 return sign
* number
;
819 static double parseFloat(const UString
&s
)
821 // Check for 0x prefix here, because toDouble allows it, but we must treat it as 0.
822 // Need to skip any whitespace and then one + or - sign.
823 int length
= s
.size();
825 while (p
< length
&& isStrWhiteSpace(s
[p
].uc
)) {
828 if (p
< length
&& (s
[p
] == '+' || s
[p
] == '-')) {
831 if (length
- p
>= 2 && s
[p
] == '0' && (s
[p
+ 1] == 'x' || s
[p
+ 1] == 'X')) {
835 return s
.toDouble( true /*tolerant*/, false /* NaN for empty string */ );
838 JSValue
*GlobalFuncImp::callAsFunction(ExecState
*exec
, JSObject
* /*thisObj*/, const List
&args
)
840 JSValue
*res
= jsUndefined();
842 static const char do_not_escape
[] =
843 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
844 "abcdefghijklmnopqrstuvwxyz"
848 static const char do_not_escape_when_encoding_URI_component
[] =
849 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
850 "abcdefghijklmnopqrstuvwxyz"
853 static const char do_not_escape_when_encoding_URI
[] =
854 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
855 "abcdefghijklmnopqrstuvwxyz"
857 "!#$&'()*+,-./:;=?@_~";
858 static const char do_not_unescape_when_decoding_URI
[] =
862 case Eval
: { // eval()
863 JSValue
*x
= args
[0];
867 UString s
= x
->toString(exec
);
872 RefPtr
<ProgramNode
> progNode(parser().parseProgram(UString(), 0, s
.data(), s
.size(), &sourceId
, &errLine
, &errMsg
));
874 Debugger
*dbg
= exec
->dynamicInterpreter()->debugger();
876 dbg
->reportSourceParsed(exec
, progNode
.get(), s
, 0, errLine
, errMsg
);
879 // no program node means a syntax occurred
881 return throwError(exec
, SyntaxError
, errMsg
, errLine
, sourceId
, NULL
);
883 // If the variable object we're working with is an activation, we better
884 // tear it off since stuff inside eval can capture it in a closure
885 if (exec
->variableObject()->isActivation())
886 static_cast<ActivationImp
*>(exec
->variableObject())->requestTearOff();
888 // enter a new execution context
889 EvalExecState
newExec(exec
->dynamicInterpreter(),
890 exec
->dynamicInterpreter()->globalObject(),
894 if (exec
->hadException())
895 newExec
.setException(exec
->exception());
898 bool cont
= dbg
->enterContext(&newExec
, sourceId
, 0, 0, List::empty());
901 return jsUndefined();
906 progNode
->processDecls(&newExec
);
907 Completion c
= progNode
->execute(&newExec
);
909 dbg
= exec
->dynamicInterpreter()->debugger();
911 bool cont
= dbg
->exitContext(&newExec
, sourceId
, 0, 0);
914 return jsUndefined();
918 // if an exception occurred, propagate it back to the previous execution object
919 if (newExec
.hadException())
920 exec
->setException(newExec
.exception());
923 if (c
.complType() == Throw
)
924 exec
->setException(c
.value());
925 else if (c
.isValueCompletion())
931 res
= jsNumber(parseInt(args
[0]->toString(exec
), args
[1]->toInt32(exec
)));
934 res
= jsNumber(parseFloat(args
[0]->toString(exec
)));
937 res
= jsBoolean(isNaN(args
[0]->toNumber(exec
)));
940 double n
= args
[0]->toNumber(exec
);
941 res
= jsBoolean(!isNaN(n
) && !isInf(n
));
945 res
= decode(exec
, args
, do_not_unescape_when_decoding_URI
);
947 case DecodeURIComponent
:
948 res
= decode(exec
, args
, "");
951 res
= encode(exec
, args
, do_not_escape_when_encoding_URI
);
953 case EncodeURIComponent
:
954 res
= encode(exec
, args
, do_not_escape_when_encoding_URI_component
);
958 UString r
= "", s
, str
= args
[0]->toString(exec
);
959 const UChar
* c
= str
.data();
960 for (int k
= 0; k
< str
.size(); k
++, c
++) {
964 sprintf(tmp
, "%%u%04X", u
);
966 } else if (u
!= 0 && strchr(do_not_escape
, (char)u
)) {
970 sprintf(tmp
, "%%%02X", u
);
980 UString s
= "", str
= args
[0]->toString(exec
);
981 int k
= 0, len
= str
.size();
983 const UChar
* c
= str
.data() + k
;
985 if (*c
== UChar('%') && k
<= len
- 6 && *(c
+1) == UChar('u')) {
986 if (Lexer::isHexDigit((c
+2)->uc
) && Lexer::isHexDigit((c
+3)->uc
) &&
987 Lexer::isHexDigit((c
+4)->uc
) && Lexer::isHexDigit((c
+5)->uc
)) {
988 u
= Lexer::convertUnicode((c
+2)->uc
, (c
+3)->uc
,
989 (c
+4)->uc
, (c
+5)->uc
);
993 } else if (*c
== UChar('%') && k
<= len
- 3 &&
994 Lexer::isHexDigit((c
+1)->uc
) && Lexer::isHexDigit((c
+2)->uc
)) {
995 u
= UChar(Lexer::convertHex((c
+1)->uc
, (c
+2)->uc
));
1007 puts(args
[0]->toString(exec
).ascii());