2006-10-31 Vladimir Olexa <vladimir.olexa@gmail.com>
[WebKit-https.git] / JavaScriptCore / kjs / function.cpp
1 // -*- c-basic-offset: 2 -*-
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  *
8  *  This library is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU Library General Public
10  *  License as published by the Free Software Foundation; either
11  *  version 2 of the License, or (at your option) any later version.
12  *
13  *  This library is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  Library General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Library General Public License
19  *  along with this library; see the file COPYING.LIB.  If not, write to
20  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  *  Boston, MA 02110-1301, USA.
22  *
23  */
24
25 #include "config.h"
26 #include "function.h"
27
28 #include "internal.h"
29 #include "function_object.h"
30 #include "lexer.h"
31 #include "nodes.h"
32 #include "operations.h"
33 #include "debugger.h"
34 #include "context.h"
35
36 #include <stdio.h>
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <assert.h>
40 #include <string.h>
41 #include <ctype.h>
42
43 #include <wtf/unicode/Unicode.h>
44
45 namespace KJS {
46
47 // ----------------------------- FunctionImp ----------------------------------
48
49 const ClassInfo FunctionImp::info = {"Function", &InternalFunctionImp::info, 0, 0};
50
51   class Parameter {
52   public:
53     Parameter() {};
54     Parameter(const Identifier& n) : name(n) { }
55     Identifier name;
56   };
57
58 FunctionImp::FunctionImp(ExecState* exec, const Identifier& n, FunctionBodyNode* b)
59   : InternalFunctionImp(static_cast<FunctionPrototype*>
60                         (exec->lexicalInterpreter()->builtinFunctionPrototype()), n)
61   , body(b)
62 {
63 }
64
65 void FunctionImp::mark()
66 {
67     InternalFunctionImp::mark();
68     _scope.mark();
69 }
70
71 FunctionImp::~FunctionImp()
72 {
73 }
74
75 JSValue* FunctionImp::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
76 {
77   JSObject* globalObj = exec->dynamicInterpreter()->globalObject();
78
79   // enter a new execution context
80   Context ctx(globalObj, exec->dynamicInterpreter(), thisObj, body.get(),
81                  codeType(), exec->context(), this, &args);
82   ExecState newExec(exec->dynamicInterpreter(), &ctx);
83   if (exec->hadException())
84     newExec.setException(exec->exception());
85   ctx.setExecState(&newExec);
86
87   // assign user supplied arguments to parameters
88   processParameters(&newExec, args);
89   // add variable declarations (initialized to undefined)
90   processVarDecls(&newExec);
91
92   Debugger* dbg = exec->dynamicInterpreter()->debugger();
93   int sid = -1;
94   int lineno = -1;
95   if (dbg) {
96     if (inherits(&DeclaredFunctionImp::info)) {
97       sid = static_cast<DeclaredFunctionImp*>(this)->body->sourceId();
98       lineno = static_cast<DeclaredFunctionImp*>(this)->body->firstLine();
99     }
100
101     bool cont = dbg->callEvent(&newExec,sid,lineno,this,args);
102     if (!cont) {
103       dbg->imp()->abort();
104       return jsUndefined();
105     }
106   }
107
108   Completion comp = execute(&newExec);
109
110   // if an exception occured, propogate it back to the previous execution object
111   if (newExec.hadException())
112     comp = Completion(Throw, newExec.exception());
113
114 #ifdef KJS_VERBOSE
115   if (comp.complType() == Throw)
116     printInfo(exec,"throwing", comp.value());
117   else if (comp.complType() == ReturnValue)
118     printInfo(exec,"returning", comp.value());
119   else
120     fprintf(stderr, "returning: undefined\n");
121 #endif
122
123   // The debugger may have been deallocated by now if the WebFrame
124   // we were running in has been destroyed, so refetch it.
125   // See http://bugzilla.opendarwin.org/show_bug.cgi?id=9477
126   dbg = exec->dynamicInterpreter()->debugger();
127
128   if (dbg) {
129     if (inherits(&DeclaredFunctionImp::info))
130       lineno = static_cast<DeclaredFunctionImp*>(this)->body->lastLine();
131
132     if (comp.complType() == Throw)
133         newExec.setException(comp.value());
134
135     int cont = dbg->returnEvent(&newExec,sid,lineno,this);
136     if (!cont) {
137       dbg->imp()->abort();
138       return jsUndefined();
139     }
140   }
141
142   if (comp.complType() == Throw) {
143     exec->setException(comp.value());
144     return comp.value();
145   }
146   else if (comp.complType() == ReturnValue)
147     return comp.value();
148   else
149     return jsUndefined();
150 }
151
152 void FunctionImp::addParameter(const Identifier& n)
153 {
154     if (!parameters)
155         parameters.set(new Vector<Parameter>);
156
157     parameters->append(Parameter(n));
158 }
159
160 UString FunctionImp::parameterString() const
161 {
162     UString s;
163
164     if (!parameters)
165         return s;
166
167     for (size_t i = 0; i < parameters->size(); ++i) {
168         if (!s.isEmpty())
169             s += ", ";
170         s += parameters->at(i).name.ustring();
171     }
172
173     return s;
174 }
175
176
177 // ECMA 10.1.3q
178 void FunctionImp::processParameters(ExecState* exec, const List& args)
179 {
180     if (!parameters)
181         return;
182
183     JSObject* variable = exec->context()->variableObject();
184
185 #ifdef KJS_VERBOSE
186     fprintf(stderr, "---------------------------------------------------\n"
187           "processing parameters for %s call\n",
188           name().isEmpty() ? "(internal)" : name().ascii());
189 #endif
190
191     ListIterator it = args.begin();
192
193     JSValue * v = *it;
194     for (size_t i = 0; i < parameters->size(); ++i) {
195       if (it != args.end()) {
196 #ifdef KJS_VERBOSE
197         fprintf(stderr, "setting parameter %s ", parameters->at(i).name.ascii());
198         printInfo(exec, "to", *it);
199 #endif
200         variable->put(exec, parameters->at(i).name, v);
201         v = ++it;
202       } else
203         variable->put(exec, parameters->at(i).name, jsUndefined());
204   }
205 #ifdef KJS_VERBOSE
206   else {
207     for (int i = 0; i < args.size(); ++i)
208       printInfo(exec,"setting argument", args[i]);
209   }
210 #endif
211 }
212
213 void FunctionImp::processVarDecls(ExecState*)
214 {
215 }
216
217 JSValue* FunctionImp::argumentsGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
218 {
219   FunctionImp* thisObj = static_cast<FunctionImp*>(slot.slotBase());
220   Context* context = exec->m_context;
221   while (context) {
222     if (context->function() == thisObj) {
223       return static_cast<ActivationImp*>(context->activationObject())->get(exec, propertyName);
224     }
225     context = context->callingContext();
226   }
227   return jsNull();
228 }
229
230 JSValue* FunctionImp::callerGetter(ExecState* exec, JSObject*, const Identifier&, const PropertySlot& slot)
231 {
232     FunctionImp* thisObj = static_cast<FunctionImp* >(slot.slotBase());
233     Context* context = exec->m_context;
234     while (context) {
235         if (context->function() == thisObj) 
236             return (context->callingContext()->function()) ? context->callingContext()->function() : jsNull();
237         
238         context = context->callingContext();
239     }
240     return jsNull();
241 }
242
243 JSValue* FunctionImp::lengthGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot)
244 {
245     FunctionImp* thisObj = static_cast<FunctionImp*>(slot.slotBase());
246     return jsNumber(thisObj->parameters ? thisObj->parameters->size() : 0);
247 }
248
249 bool FunctionImp::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
250 {
251     // Find the arguments from the closest context.
252     if (propertyName == exec->dynamicInterpreter()->argumentsIdentifier()) {
253         slot.setCustom(this, argumentsGetter);
254         return true;
255     }
256
257     // Compute length of parameters.
258     if (propertyName == lengthPropertyName) {
259         slot.setCustom(this, lengthGetter);
260         return true;
261     }
262
263     if (propertyName == callerPropertyName) {
264         slot.setCustom(this, callerGetter);
265         return true;
266     }
267
268     return InternalFunctionImp::getOwnPropertySlot(exec, propertyName, slot);
269 }
270
271 void FunctionImp::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)
272 {
273     if (propertyName == exec->dynamicInterpreter()->argumentsIdentifier() || propertyName == lengthPropertyName)
274         return;
275     InternalFunctionImp::put(exec, propertyName, value, attr);
276 }
277
278 bool FunctionImp::deleteProperty(ExecState* exec, const Identifier& propertyName)
279 {
280     if (propertyName == exec->dynamicInterpreter()->argumentsIdentifier() || propertyName == lengthPropertyName)
281         return false;
282     return InternalFunctionImp::deleteProperty(exec, propertyName);
283 }
284
285 /* Returns the parameter name corresponding to the given index. eg:
286  * function f1(x, y, z): getParameterName(0) --> x
287  *
288  * If a name appears more than once, only the last index at which
289  * it appears associates with it. eg:
290  * function f2(x, x): getParameterName(0) --> null
291  */
292 Identifier FunctionImp::getParameterName(int index)
293 {
294     if (!parameters)
295         return Identifier::null();
296
297     if (static_cast<size_t>(index) >= parameters->size())
298         return Identifier::null();
299   
300     Identifier name = parameters->at(index).name;
301
302     // Are there any subsequent parameters with the same name?
303     for (size_t i = index + 1; i < parameters->size(); ++i)
304         if (parameters->at(i).name == name)
305             return Identifier::null();
306
307     return name;
308 }
309
310 // ------------------------------ DeclaredFunctionImp --------------------------
311
312 // ### is "Function" correct here?
313 const ClassInfo DeclaredFunctionImp::info = {"Function", &FunctionImp::info, 0, 0};
314
315 DeclaredFunctionImp::DeclaredFunctionImp(ExecState* exec, const Identifier& n,
316                                          FunctionBodyNode* b, const ScopeChain& sc)
317   : FunctionImp(exec, n, b)
318 {
319   setScope(sc);
320 }
321
322 bool DeclaredFunctionImp::implementsConstruct() const
323 {
324   return true;
325 }
326
327 // ECMA 13.2.2 [[Construct]]
328 JSObject* DeclaredFunctionImp::construct(ExecState* exec, const List& args)
329 {
330   JSObject* proto;
331   JSValue* p = get(exec,prototypePropertyName);
332   if (p->isObject())
333     proto = static_cast<JSObject*>(p);
334   else
335     proto = exec->lexicalInterpreter()->builtinObjectPrototype();
336
337   JSObject* obj(new JSObject(proto));
338
339   JSValue* res = call(exec,obj,args);
340
341   if (res->isObject())
342     return static_cast<JSObject*>(res);
343   else
344     return obj;
345 }
346
347 Completion DeclaredFunctionImp::execute(ExecState* exec)
348 {
349   Completion result = body->execute(exec);
350
351   if (result.complType() == Throw || result.complType() == ReturnValue)
352       return result;
353   return Completion(Normal, jsUndefined()); // TODO: or ReturnValue ?
354 }
355
356 void DeclaredFunctionImp::processVarDecls(ExecState* exec)
357 {
358   body->processVarDecls(exec);
359 }
360
361 // ------------------------------ IndexToNameMap ---------------------------------
362
363 // We map indexes in the arguments array to their corresponding argument names. 
364 // Example: function f(x, y, z): arguments[0] = x, so we map 0 to Identifier("x"). 
365
366 // Once we have an argument name, we can get and set the argument's value in the 
367 // activation object.
368
369 // We use Identifier::null to indicate that a given argument's value
370 // isn't stored in the activation object.
371
372 IndexToNameMap::IndexToNameMap(FunctionImp* func, const List& args)
373 {
374   _map = new Identifier[args.size()];
375   this->size = args.size();
376   
377   int i = 0;
378   ListIterator iterator = args.begin(); 
379   for (; iterator != args.end(); i++, iterator++)
380     _map[i] = func->getParameterName(i); // null if there is no corresponding parameter
381 }
382
383 IndexToNameMap::~IndexToNameMap() {
384   delete [] _map;
385 }
386
387 bool IndexToNameMap::isMapped(const Identifier& index) const
388 {
389   bool indexIsNumber;
390   int indexAsNumber = index.toUInt32(&indexIsNumber);
391   
392   if (!indexIsNumber)
393     return false;
394   
395   if (indexAsNumber >= size)
396     return false;
397
398   if (_map[indexAsNumber].isNull())
399     return false;
400   
401   return true;
402 }
403
404 void IndexToNameMap::unMap(const Identifier& index)
405 {
406   bool indexIsNumber;
407   int indexAsNumber = index.toUInt32(&indexIsNumber);
408
409   assert(indexIsNumber && indexAsNumber < size);
410   
411   _map[indexAsNumber] = Identifier::null();
412 }
413
414 Identifier& IndexToNameMap::operator[](int index)
415 {
416   return _map[index];
417 }
418
419 Identifier& IndexToNameMap::operator[](const Identifier& index)
420 {
421   bool indexIsNumber;
422   int indexAsNumber = index.toUInt32(&indexIsNumber);
423
424   assert(indexIsNumber && indexAsNumber < size);
425   
426   return (*this)[indexAsNumber];
427 }
428
429 // ------------------------------ Arguments ---------------------------------
430
431 const ClassInfo Arguments::info = {"Arguments", 0, 0, 0};
432
433 // ECMA 10.1.8
434 Arguments::Arguments(ExecState* exec, FunctionImp* func, const List& args, ActivationImp* act)
435 : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()), 
436 _activationObject(act),
437 indexToNameMap(func, args)
438 {
439   putDirect(calleePropertyName, func, DontEnum);
440   putDirect(lengthPropertyName, args.size(), DontEnum);
441   
442   int i = 0;
443   ListIterator iterator = args.begin(); 
444   for (; iterator != args.end(); i++, iterator++) {
445     if (!indexToNameMap.isMapped(Identifier::from(i))) {
446       JSObject::put(exec, Identifier::from(i), *iterator, DontEnum);
447     }
448   }
449 }
450
451 void Arguments::mark() 
452 {
453   JSObject::mark();
454   if (_activationObject && !_activationObject->marked())
455     _activationObject->mark();
456 }
457
458 JSValue* Arguments::mappedIndexGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
459 {
460   Arguments* thisObj = static_cast<Arguments*>(slot.slotBase());
461   return thisObj->_activationObject->get(exec, thisObj->indexToNameMap[propertyName]);
462 }
463
464 bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
465 {
466   if (indexToNameMap.isMapped(propertyName)) {
467     slot.setCustom(this, mappedIndexGetter);
468     return true;
469   }
470
471   return JSObject::getOwnPropertySlot(exec, propertyName, slot);
472 }
473
474 void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)
475 {
476   if (indexToNameMap.isMapped(propertyName)) {
477     _activationObject->put(exec, indexToNameMap[propertyName], value, attr);
478   } else {
479     JSObject::put(exec, propertyName, value, attr);
480   }
481 }
482
483 bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName) 
484 {
485   if (indexToNameMap.isMapped(propertyName)) {
486     indexToNameMap.unMap(propertyName);
487     return true;
488   } else {
489     return JSObject::deleteProperty(exec, propertyName);
490   }
491 }
492
493 // ------------------------------ ActivationImp --------------------------------
494
495 const ClassInfo ActivationImp::info = {"Activation", 0, 0, 0};
496
497 // ECMA 10.1.6
498 ActivationImp::ActivationImp(FunctionImp* function, const List& arguments)
499     : _function(function), _arguments(true), _argumentsObject(0)
500 {
501   _arguments.copyFrom(arguments);
502   // FIXME: Do we need to support enumerating the arguments property?
503 }
504
505 JSValue* ActivationImp::argumentsGetter(ExecState* exec, JSObject*, const Identifier&, const PropertySlot& slot)
506 {
507   ActivationImp* thisObj = static_cast<ActivationImp*>(slot.slotBase());
508
509   // default: return builtin arguments array
510   if (!thisObj->_argumentsObject)
511     thisObj->createArgumentsObject(exec);
512   
513   return thisObj->_argumentsObject;
514 }
515
516 PropertySlot::GetValueFunc ActivationImp::getArgumentsGetter()
517 {
518   return ActivationImp::argumentsGetter;
519 }
520
521 bool ActivationImp::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
522 {
523     // do this first so property map arguments property wins over the below
524     // we don't call JSObject because we won't have getter/setter properties
525     // and we don't want to support __proto__
526
527     if (JSValue** location = getDirectLocation(propertyName)) {
528         slot.setValueSlot(this, location);
529         return true;
530     }
531
532     if (propertyName == exec->dynamicInterpreter()->argumentsIdentifier()) {
533         slot.setCustom(this, getArgumentsGetter());
534         return true;
535     }
536
537     return false;
538 }
539
540 bool ActivationImp::deleteProperty(ExecState* exec, const Identifier& propertyName)
541 {
542     if (propertyName == exec->dynamicInterpreter()->argumentsIdentifier())
543         return false;
544     return JSObject::deleteProperty(exec, propertyName);
545 }
546
547 void ActivationImp::put(ExecState*, const Identifier& propertyName, JSValue* value, int attr)
548 {
549   // There's no way that an activation object can have a prototype or getter/setter properties
550   assert(!_prop.hasGetterSetterProperties());
551   assert(prototype() == jsNull());
552
553   _prop.put(propertyName, value, attr, (attr == None || attr == DontDelete));
554 }
555
556 void ActivationImp::mark()
557 {
558     if (_function && !_function->marked()) 
559         _function->mark();
560     _arguments.mark();
561     if (_argumentsObject && !_argumentsObject->marked())
562         _argumentsObject->mark();
563     JSObject::mark();
564 }
565
566 void ActivationImp::createArgumentsObject(ExecState* exec) const
567 {
568   _argumentsObject = new Arguments(exec, _function, _arguments, const_cast<ActivationImp*>(this));
569 }
570
571 // ------------------------------ GlobalFunc -----------------------------------
572
573
574 GlobalFuncImp::GlobalFuncImp(ExecState*, FunctionPrototype* funcProto, int i, int len, const Identifier& name)
575   : InternalFunctionImp(funcProto, name)
576   , id(i)
577 {
578   putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
579 }
580
581 CodeType GlobalFuncImp::codeType() const
582 {
583   return id == Eval ? EvalCode : codeType();
584 }
585
586 static JSValue* encode(ExecState* exec, const List& args, const char* do_not_escape)
587 {
588   UString r = "", s, str = args[0]->toString(exec);
589   CString cstr = str.UTF8String();
590   const char* p = cstr.c_str();
591   for (size_t k = 0; k < cstr.size(); k++, p++) {
592     char c = *p;
593     if (c && strchr(do_not_escape, c)) {
594       r.append(c);
595     } else {
596       char tmp[4];
597       sprintf(tmp, "%%%02X", (unsigned char)c);
598       r += tmp;
599     }
600   }
601   return jsString(r);
602 }
603
604 static JSValue* decode(ExecState* exec, const List& args, const char* do_not_unescape, bool strict)
605 {
606   UString s = "", str = args[0]->toString(exec);
607   int k = 0, len = str.size();
608   const UChar* d = str.data();
609   UChar u;
610   while (k < len) {
611     const UChar* p = d + k;
612     UChar c = *p;
613     if (c == '%') {
614       int charLen = 0;
615       if (k <= len - 3 && isxdigit(p[1].uc) && isxdigit(p[2].uc)) {
616         const char b0 = Lexer::convertHex(p[1].uc, p[2].uc);
617         const int sequenceLen = UTF8SequenceLength(b0);
618         if (sequenceLen != 0 && k <= len - sequenceLen * 3) {
619           charLen = sequenceLen * 3;
620           char sequence[5];
621           sequence[0] = b0;
622           for (int i = 1; i < sequenceLen; ++i) {
623             const UChar* q = p + i * 3;
624             if (q[0] == '%' && isxdigit(q[1].uc) && isxdigit(q[2].uc))
625               sequence[i] = Lexer::convertHex(q[1].uc, q[2].uc);
626             else {
627               charLen = 0;
628               break;
629             }
630           }
631           if (charLen != 0) {
632             sequence[sequenceLen] = 0;
633             const int character = decodeUTF8Sequence(sequence);
634             if (character < 0 || character >= 0x110000) {
635               charLen = 0;
636             } else if (character >= 0x10000) {
637               // Convert to surrogate pair.
638               s.append(static_cast<unsigned short>(0xD800 | ((character - 0x10000) >> 10)));
639               u = static_cast<unsigned short>(0xDC00 | ((character - 0x10000) & 0x3FF));
640             } else {
641               u = static_cast<unsigned short>(character);
642             }
643           }
644         }
645       }
646       if (charLen == 0) {
647         if (strict)
648           return throwError(exec, URIError);
649         // The only case where we don't use "strict" mode is the "unescape" function.
650         // For that, it's good to support the wonky "%u" syntax for compatibility with WinIE.
651         if (k <= len - 6 && p[1] == 'u'
652             && isxdigit(p[2].uc) && isxdigit(p[3].uc)
653             && isxdigit(p[4].uc) && isxdigit(p[5].uc)) {
654           charLen = 6;
655           u = Lexer::convertUnicode(p[2].uc, p[3].uc, p[4].uc, p[5].uc);
656         }
657       }
658       if (charLen && (u.uc == 0 || u.uc >= 128 || !strchr(do_not_unescape, u.low()))) {
659         c = u;
660         k += charLen - 1;
661       }
662     }
663     k++;
664     s.append(c);
665   }
666   return jsString(s);
667 }
668
669 static bool isStrWhiteSpace(unsigned short c)
670 {
671     switch (c) {
672         case 0x0009:
673         case 0x000A:
674         case 0x000B:
675         case 0x000C:
676         case 0x000D:
677         case 0x0020:
678         case 0x00A0:
679         case 0x2028:
680         case 0x2029:
681             return true;
682         default:
683             return WTF::Unicode::isSeparatorSpace(c);
684     }
685 }
686
687 static int parseDigit(unsigned short c, int radix)
688 {
689     int digit = -1;
690
691     if (c >= '0' && c <= '9') {
692         digit = c - '0';
693     } else if (c >= 'A' && c <= 'Z') {
694         digit = c - 'A' + 10;
695     } else if (c >= 'a' && c <= 'z') {
696         digit = c - 'a' + 10;
697     }
698
699     if (digit >= radix)
700         return -1;
701     return digit;
702 }
703
704 static double parseInt(const UString& s, int radix)
705 {
706     int length = s.size();
707     int p = 0;
708
709     while (p < length && isStrWhiteSpace(s[p].uc)) {
710         ++p;
711     }
712
713     double sign = 1;
714     if (p < length) {
715         if (s[p] == '+') {
716             ++p;
717         } else if (s[p] == '-') {
718             sign = -1;
719             ++p;
720         }
721     }
722
723     if ((radix == 0 || radix == 16) && length - p >= 2 && s[p] == '0' && (s[p + 1] == 'x' || s[p + 1] == 'X')) {
724         radix = 16;
725         p += 2;
726     } else if (radix == 0) {
727         if (p < length && s[p] == '0')
728             radix = 8;
729         else
730             radix = 10;
731     }
732
733     if (radix < 2 || radix > 36)
734         return NaN;
735
736     bool sawDigit = false;
737     double number = 0;
738     while (p < length) {
739         int digit = parseDigit(s[p].uc, radix);
740         if (digit == -1)
741             break;
742         sawDigit = true;
743         number *= radix;
744         number += digit;
745         ++p;
746     }
747
748     if (!sawDigit)
749         return NaN;
750
751     return sign * number;
752 }
753
754 static double parseFloat(const UString& s)
755 {
756     // Check for 0x prefix here, because toDouble allows it, but we must treat it as 0.
757     // Need to skip any whitespace and then one + or - sign.
758     int length = s.size();
759     int p = 0;
760     while (p < length && isStrWhiteSpace(s[p].uc)) {
761         ++p;
762     }
763     if (p < length && (s[p] == '+' || s[p] == '-')) {
764         ++p;
765     }
766     if (length - p >= 2 && s[p] == '0' && (s[p + 1] == 'x' || s[p + 1] == 'X')) {
767         return 0;
768     }
769
770     return s.toDouble( true /*tolerant*/, false /* NaN for empty string */ );
771 }
772
773 JSValue* GlobalFuncImp::callAsFunction(ExecState* exec, JSObject* /*thisObj*/, const List& args)
774 {
775   JSValue* res = jsUndefined();
776
777   static const char do_not_escape[] =
778     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
779     "abcdefghijklmnopqrstuvwxyz"
780     "0123456789"
781     "*+-./@_";
782
783   static const char do_not_escape_when_encoding_URI_component[] =
784     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
785     "abcdefghijklmnopqrstuvwxyz"
786     "0123456789"
787     "!'()*-._~";
788   static const char do_not_escape_when_encoding_URI[] =
789     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
790     "abcdefghijklmnopqrstuvwxyz"
791     "0123456789"
792     "!#$&'()*+,-./:;=?@_~";
793   static const char do_not_unescape_when_decoding_URI[] =
794     "#$&+,/:;=?@";
795
796   switch (id) {
797     case Eval: { // eval()
798       JSValue* x = args[0];
799       if (!x->isString())
800         return x;
801       else {
802         UString s = x->toString(exec);
803         
804         int sid;
805         int errLine;
806         UString errMsg;
807         RefPtr<ProgramNode> progNode(Parser::parse(UString(), 0, s.data(),s.size(),&sid,&errLine,&errMsg));
808
809         Debugger* dbg = exec->dynamicInterpreter()->debugger();
810         if (dbg) {
811           bool cont = dbg->sourceParsed(exec, sid, UString(), s, 0, errLine, errMsg);
812           if (!cont)
813             return jsUndefined();
814         }
815
816         // no program node means a syntax occurred
817         if (!progNode)
818           return throwError(exec, SyntaxError, errMsg, errLine, sid, NULL);
819
820         // enter a new execution context
821         JSObject* thisVal = static_cast<JSObject*>(exec->context()->thisValue());
822         Context ctx(exec->dynamicInterpreter()->globalObject(),
823                        exec->dynamicInterpreter(),
824                        thisVal,
825                        progNode.get(),
826                        EvalCode,
827                        exec->context());
828         ExecState newExec(exec->dynamicInterpreter(), &ctx);
829         if (exec->hadException())
830             newExec.setException(exec->exception());
831         ctx.setExecState(&newExec);
832         
833         // execute the code
834         progNode->processVarDecls(&newExec);
835         Completion c = progNode->execute(&newExec);
836
837         // if an exception occured, propogate it back to the previous execution object
838         if (newExec.hadException())
839           exec->setException(newExec.exception());
840
841         res = jsUndefined();
842         if (c.complType() == Throw)
843           exec->setException(c.value());
844         else if (c.isValueCompletion())
845             res = c.value();
846       }
847       break;
848     }
849   case ParseInt:
850     res = jsNumber(parseInt(args[0]->toString(exec), args[1]->toInt32(exec)));
851     break;
852   case ParseFloat:
853     res = jsNumber(parseFloat(args[0]->toString(exec)));
854     break;
855   case IsNaN:
856     res = jsBoolean(isNaN(args[0]->toNumber(exec)));
857     break;
858   case IsFinite: {
859     double n = args[0]->toNumber(exec);
860     res = jsBoolean(!isNaN(n) && !isInf(n));
861     break;
862   }
863   case DecodeURI:
864     res = decode(exec, args, do_not_unescape_when_decoding_URI, true);
865     break;
866   case DecodeURIComponent:
867     res = decode(exec, args, "", true);
868     break;
869   case EncodeURI:
870     res = encode(exec, args, do_not_escape_when_encoding_URI);
871     break;
872   case EncodeURIComponent:
873     res = encode(exec, args, do_not_escape_when_encoding_URI_component);
874     break;
875   case Escape:
876     {
877       UString r = "", s, str = args[0]->toString(exec);
878       const UChar* c = str.data();
879       for (int k = 0; k < str.size(); k++, c++) {
880         int u = c->uc;
881         if (u > 255) {
882           char tmp[7];
883           sprintf(tmp, "%%u%04X", u);
884           s = UString(tmp);
885         } else if (u != 0 && strchr(do_not_escape, (char)u)) {
886           s = UString(c, 1);
887         } else {
888           char tmp[4];
889           sprintf(tmp, "%%%02X", u);
890           s = UString(tmp);
891         }
892         r += s;
893       }
894       res = jsString(r);
895       break;
896     }
897   case UnEscape:
898     {
899       UString s = "", str = args[0]->toString(exec);
900       int k = 0, len = str.size();
901       while (k < len) {
902         const UChar* c = str.data() + k;
903         UChar u;
904         if (*c == UChar('%') && k <= len - 6 && *(c+1) == UChar('u')) {
905           if (Lexer::isHexDigit((c+2)->uc) && Lexer::isHexDigit((c+3)->uc) &&
906               Lexer::isHexDigit((c+4)->uc) && Lexer::isHexDigit((c+5)->uc)) {
907           u = Lexer::convertUnicode((c+2)->uc, (c+3)->uc,
908                                     (c+4)->uc, (c+5)->uc);
909           c = &u;
910           k += 5;
911           }
912         } else if (*c == UChar('%') && k <= len - 3 &&
913                    Lexer::isHexDigit((c+1)->uc) && Lexer::isHexDigit((c+2)->uc)) {
914           u = UChar(Lexer::convertHex((c+1)->uc, (c+2)->uc));
915           c = &u;
916           k += 2;
917         }
918         k++;
919         s += UString(c, 1);
920       }
921       res = jsString(s);
922       break;
923     }
924 #ifndef NDEBUG
925   case KJSPrint:
926     puts(args[0]->toString(exec).ascii());
927     break;
928 #endif
929   }
930
931   return res;
932 }
933
934 UString escapeStringForPrettyPrinting(const UString& s)
935 {
936     UString escapedString;
937     
938     for (int i = 0; i < s.size(); i++) {
939         unsigned short c = s.data()[i].unicode();
940         
941         switch (c) {
942         case '\"':
943             escapedString += "\\\"";
944             break;
945         case '\n':
946             escapedString += "\\n";
947             break;
948         case '\r':
949             escapedString += "\\r";
950             break;
951         case '\t':
952             escapedString += "\\t";
953             break;
954         case '\\':
955             escapedString += "\\\\";
956             break;
957         default:
958             if (c < 128 && WTF::Unicode::isPrintableChar(c))
959                 escapedString.append(c);
960             else {
961                 char hexValue[7];
962             
963 #if PLATFORM(WIN_OS)
964                 _snprintf(hexValue, 7, "\\u%04x", c);
965 #else
966                 snprintf(hexValue, 7, "\\u%04x", c);
967 #endif
968                 escapedString += hexValue;
969             }
970         }
971     }
972     
973     return escapedString;    
974 }
975
976 } // namespace