• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kjs
 

kjs

  • kjs
function.cpp
1/*
2 * This file is part of the KDE libraries
3 * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
4 * Copyright (C) 2001,2003 Peter Kelly (pmk@post.com)
5 * Copyright (C) 2003 Apple Computer, Inc.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24#include "function.h"
25
26#include "internal.h"
27#include "function_object.h"
28#include "lexer.h"
29#include "nodes.h"
30#include "operations.h"
31#include "debugger.h"
32#include "context.h"
33
34#include <stdio.h>
35#include <errno.h>
36#include <stdlib.h>
37#include <assert.h>
38#include <string.h>
39#include <math.h>
40#include <ctype.h>
41
42using namespace KJS;
43
44// ------------------------- URI handling functions ---------------------------
45
46// ECMA 15.1.3
47UString encodeURI(ExecState *exec, UString string, UString unescapedSet)
48{
49 char hexdigits[] = "0123456789ABCDEF";
50 int encbufAlloc = 2;
51 UChar *encbuf = (UChar*)malloc(encbufAlloc*sizeof(UChar));
52 int encbufLen = 0;
53
54 for (int k = 0; k < string.size(); k++) {
55
56 UChar C = string[k];
57 if (unescapedSet.find(C) >= 0) {
58 if (encbufLen+1 >= encbufAlloc)
59 encbuf = (UChar*)realloc(encbuf,(encbufAlloc *= 2)*sizeof(UChar));
60 encbuf[encbufLen++] = C;
61 }
62 else {
63 unsigned char octets[4];
64 int octets_len = 0;
65 if (C.uc <= 0x007F) {
66 unsigned short zzzzzzz = C.uc;
67 octets[0] = zzzzzzz;
68 octets_len = 1;
69 }
70 else if (C.uc <= 0x07FF) {
71 unsigned short zzzzzz = C.uc & 0x3F;
72 unsigned short yyyyy = (C.uc >> 6) & 0x1F;
73 octets[0] = 0xC0 | yyyyy;
74 octets[1] = 0x80 | zzzzzz;
75 octets_len = 2;
76 }
77 else if (C.uc >= 0xD800 && C.uc <= 0xDBFF) {
78
79 // we need two chars
80 if (k + 1 >= string.size()) {
81 Object err = Error::create(exec,URIError);
82 exec->setException(err);
83 free(encbuf);
84 return UString("");
85 }
86
87 unsigned short Cnext = UChar(string[++k]).uc;
88
89 if (Cnext < 0xDC00 || Cnext > 0xDFFF) {
90 Object err = Error::create(exec,URIError);
91 exec->setException(err);
92 free(encbuf);
93 return UString("");
94 }
95
96 unsigned short zzzzzz = Cnext & 0x3F;
97 unsigned short yyyy = (Cnext >> 6) & 0x0F;
98 unsigned short xx = C.uc & 0x03;
99 unsigned short wwww = (C.uc >> 2) & 0x0F;
100 unsigned short vvvv = (C.uc >> 6) & 0x0F;
101 unsigned short uuuuu = vvvv+1;
102 octets[0] = 0xF0 | (uuuuu >> 2);
103 octets[1] = 0x80 | ((uuuuu & 0x03) << 4) | wwww;
104 octets[2] = 0x80 | (xx << 4) | yyyy;
105 octets[3] = 0x80 | zzzzzz;
106 octets_len = 4;
107 }
108 else if (C.uc >= 0xDC00 && C.uc <= 0xDFFF) {
109 Object err = Error::create(exec,URIError);
110 exec->setException(err);
111 free(encbuf);
112 return UString("");
113 }
114 else {
115 // 0x0800 - 0xD7FF or 0xE000 - 0xFFFF
116 unsigned short zzzzzz = C.uc & 0x3F;
117 unsigned short yyyyyy = (C.uc >> 6) & 0x3F;
118 unsigned short xxxx = (C.uc >> 12) & 0x0F;
119 octets[0] = 0xE0 | xxxx;
120 octets[1] = 0x80 | yyyyyy;
121 octets[2] = 0x80 | zzzzzz;
122 octets_len = 3;
123 }
124
125 while (encbufLen+3*octets_len >= encbufAlloc)
126 encbuf = (UChar*)realloc(encbuf,(encbufAlloc *= 2)*sizeof(UChar));
127
128 for (int j = 0; j < octets_len; j++) {
129 encbuf[encbufLen++] = '%';
130 encbuf[encbufLen++] = hexdigits[octets[j] >> 4];
131 encbuf[encbufLen++] = hexdigits[octets[j] & 0x0F];
132 }
133 }
134 }
135
136 UString encoded(encbuf,encbufLen);
137 free(encbuf);
138 return encoded;
139}
140
141static bool decodeHex(UChar hi, UChar lo, unsigned short *val)
142{
143 *val = 0;
144 if (hi.uc >= '0' && hi.uc <= '9')
145 *val = (hi.uc-'0') << 4;
146 else if (hi.uc >= 'a' && hi.uc <= 'f')
147 *val = 10+(hi.uc-'a') << 4;
148 else if (hi.uc >= 'A' && hi.uc <= 'F')
149 *val = 10+(hi.uc-'A') << 4;
150 else
151 return false;
152
153 if (lo.uc >= '0' && lo.uc <= '9')
154 *val |= (lo.uc-'0');
155 else if (lo.uc >= 'a' && lo.uc <= 'f')
156 *val |= 10+(lo.uc-'a');
157 else if (lo.uc >= 'A' && lo.uc <= 'F')
158 *val |= 10+(lo.uc-'A');
159 else
160 return false;
161
162 return true;
163}
164
165UString decodeURI(ExecState *exec, UString string, UString reservedSet)
166{
167 int decbufAlloc = 2;
168 UChar *decbuf = (UChar*)malloc(decbufAlloc*sizeof(UChar));
169 int decbufLen = 0;
170
171 for (int k = 0; k < string.size(); k++) {
172 UChar C = string[k];
173
174 if (C != UChar('%')) {
175 // Normal unescaped character
176 if (decbufLen+1 >= decbufAlloc)
177 decbuf = (UChar*)realloc(decbuf,(decbufAlloc *= 2)*sizeof(UChar));
178 decbuf[decbufLen++] = C;
179 continue;
180 }
181
182 // We have % escape sequence... expect at least 2 more characters
183 int start = k;
184 if (k+2 >= string.size()) {
185 Object err = Error::create(exec,URIError);
186 exec->setException(err);
187 free(decbuf);
188 return UString("");
189 }
190
191 unsigned short B;
192 if (!decodeHex(string[k+1],string[k+2],&B)) {
193 Object err = Error::create(exec,URIError);
194 exec->setException(err);
195 free(decbuf);
196 return UString("");
197 }
198
199 k += 2;
200
201 if (decbufLen+2 >= decbufAlloc)
202 decbuf = (UChar*)realloc(decbuf,(decbufAlloc *= 2)*sizeof(UChar));
203
204 if ((B & 0x80) == 0) {
205 // Single-byte character
206 C = B;
207 }
208 else {
209 // Multi-byte character
210 int n = 0;
211 while (((B << n) & 0x80) != 0)
212 n++;
213
214 if (n < 2 || n > 4) {
215 Object err = Error::create(exec,URIError);
216 exec->setException(err);
217 free(decbuf);
218 return UString("");
219 }
220
221 if (k+3*(n-1) >= string.size()) {
222 Object err = Error::create(exec,URIError);
223 exec->setException(err);
224 free(decbuf);
225 return UString("");
226 }
227
228 unsigned short octets[4];
229 octets[0] = B;
230 for (int j = 1; j < n; j++) {
231 k++;
232 if ((UChar(string[k]) != UChar('%')) ||
233 !decodeHex(string[k+1],string[k+2],&B) ||
234 ((B & 0xC0) != 0x80)) {
235 Object err = Error::create(exec,URIError);
236 exec->setException(err);
237 free(decbuf);
238 return UString("");
239 }
240
241 k += 2;
242 octets[j] = B;
243 }
244
245 // UTF-8 transform
246 const unsigned long replacementChar = 0xFFFD;
247 unsigned long V;
248 if (n == 2) {
249 unsigned long yyyyy = octets[0] & 0x1F;
250 unsigned long zzzzzz = octets[1] & 0x3F;
251 V = (yyyyy << 6) | zzzzzz;
252 // 2-byte sequence overlong for this value?
253 if (V < 0x80)
254 V = replacementChar;
255 C = UChar((unsigned short)V);
256 }
257 else if (n == 3) {
258 unsigned long xxxx = octets[0] & 0x0F;
259 unsigned long yyyyyy = octets[1] & 0x3F;
260 unsigned long zzzzzz = octets[2] & 0x3F;
261 V = (xxxx << 12) | (yyyyyy << 6) | zzzzzz;
262 // 3-byte sequence overlong for this value,
263 // an invalid value or UTF-16 surrogate?
264 if (V < 0x800 || V == 0xFFFE || V == 0xFFFF ||
265 (V >= 0xD800 && V <= 0xDFFF))
266 V = replacementChar;
267 C = UChar((unsigned short)V);
268 }
269 else {
270 assert(n == 4);
271 unsigned long uuuuu = ((octets[0] & 0x07) << 2) | ((octets[1] >> 4) & 0x03);
272 unsigned long vvvv = uuuuu-1;
273 if (vvvv > 0x0F) {
274 Object err = Error::create(exec,URIError);
275 exec->setException(err);
276 free(decbuf);
277 return UString("");
278 }
279 unsigned long wwww = octets[1] & 0x0F;
280 unsigned long xx = (octets[2] >> 4) & 0x03;
281 unsigned long yyyy = octets[2] & 0x0F;
282 unsigned long zzzzzz = octets[3] & 0x3F;
283 unsigned short H = 0xD800 | (vvvv << 6) | (wwww << 2) | xx;
284 unsigned short L = 0xDC00 | (yyyy << 6) | zzzzzz;
285 decbuf[decbufLen++] = UChar(H);
286 decbuf[decbufLen++] = UChar(L);
287 continue;
288 }
289 }
290
291 if (reservedSet.find(C) < 0) {
292 decbuf[decbufLen++] = C;
293 }
294 else {
295 // copy unencoded sequence
296 while (decbufLen+k-start+1 >= decbufAlloc)
297 decbuf = (UChar*)realloc(decbuf,(decbufAlloc *= 2)*sizeof(UChar));
298 for (int p = start; p <= k; p++)
299 decbuf[decbufLen++] = string[p];
300 }
301 }
302
303 UString decoded(decbuf,decbufLen);
304 free(decbuf);
305 return decoded;
306}
307
308static UString uriReserved = ";/?:@&=+$,";
309static UString uriAlpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
310static UString DecimalDigit = "0123456789";
311static UString uriMark = "-_.!~*'()";
312static UString uriUnescaped = uriAlpha+DecimalDigit+uriMark;
313
314// ----------------------------- FunctionImp ----------------------------------
315
316const ClassInfo FunctionImp::info = {"Function", &InternalFunctionImp::info, 0, 0};
317
318namespace KJS {
319 class Parameter {
320 public:
321 Parameter(const Identifier &n) : name(n), next(0L) { }
322 ~Parameter() { delete next; }
323 Identifier name;
324 Parameter *next;
325 };
326}
327
328FunctionImp::FunctionImp(ExecState *exec, const Identifier &n)
329 : InternalFunctionImp(
330 static_cast<FunctionPrototypeImp*>(exec->lexicalInterpreter()->builtinFunctionPrototype().imp())
331 ), param(0L), line0(-1), line1(-1), sid(-1)
332{
333 //fprintf(stderr,"FunctionImp::FunctionImp this=%p\n");
334 ident = n;
335}
336
337FunctionImp::~FunctionImp()
338{
339 delete param;
340}
341
342bool FunctionImp::implementsCall() const
343{
344 return true;
345}
346
347Value FunctionImp::call(ExecState *exec, Object &thisObj, const List &args)
348{
349 Object &globalObj = exec->dynamicInterpreter()->globalObject();
350
351 // enter a new execution context
352 ContextImp ctx(globalObj, exec->dynamicInterpreter()->imp(), thisObj, sid, codeType(),
353 exec->context().imp(), this, &args);
354 ExecState newExec(exec->dynamicInterpreter(), &ctx);
355 newExec.setException(exec->exception()); // could be null
356
357 // assign user supplied arguments to parameters
358 processParameters(&newExec, args);
359 // add variable declarations (initialized to undefined)
360 processVarDecls(&newExec);
361
362 ctx.setLines(line0,line0);
363 Debugger *dbg = exec->interpreter()->imp()->debugger();
364 if (dbg) {
365 if (!dbg->enterContext(&newExec)) {
366 // debugger requested we stop execution
367 dbg->imp()->abort();
368 return Undefined();
369 }
370 }
371
372 Completion comp = execute(&newExec);
373
374 ctx.setLines(line1,line1);
375 if (dbg) {
376 Object func(this);
377 // ### lineno is inaccurate - we really want the end of the function _body_ here
378 // line1 is suppoed to be the end of the function start, just before the body
379 if (!dbg->exitContext(&newExec,comp)) {
380 // debugger requested we stop execution
381 dbg->imp()->abort();
382 return Undefined();
383 }
384 }
385
386 // if an exception occurred, propogate it back to the previous execution object
387 if (newExec.hadException())
388 exec->setException(newExec.exception());
389
390#ifdef KJS_VERBOSE
391 CString n = ident.isEmpty() ? CString("(internal)") : ident.ustring().cstring();
392 if (comp.complType() == Throw) {
393 n += " throws";
394 printInfo(exec, n.c_str(), comp.value());
395 } else if (comp.complType() == ReturnValue) {
396 n += " returns";
397 printInfo(exec, n.c_str(), comp.value());
398 } else
399 fprintf(stderr, "%s returns: undefined\n", n.c_str());
400#endif
401
402 if (comp.complType() == Throw) {
403 exec->setException(comp.value());
404 return comp.value();
405 }
406 else if (comp.complType() == ReturnValue)
407 return comp.value();
408 else
409 return Undefined();
410}
411
412void FunctionImp::addParameter(const Identifier &n)
413{
414 Parameter **p = &param;
415 while (*p)
416 p = &(*p)->next;
417
418 *p = new Parameter(n);
419}
420
421Identifier FunctionImp::parameterProperty(int index) const
422{
423 // Find the property name corresponding to the given parameter
424 int pos = 0;
425 Parameter *p;
426 for (p = param; p && pos < index; p = p->next)
427 pos++;
428
429 if (!p)
430 return Identifier::null();
431
432 // Are there any subsequent parameters with the same name?
433 Identifier name = p->name;
434 for (p = p->next; p; p = p->next)
435 if (p->name == name)
436 return Identifier::null();
437
438 return name;
439}
440
441UString FunctionImp::parameterString() const
442{
443 UString s;
444 const Parameter *p = param;
445 while (p) {
446 if (!s.isEmpty())
447 s += ", ";
448 s += p->name.ustring();
449 p = p->next;
450 }
451
452 return s;
453}
454
455
456// ECMA 10.1.3q
457void FunctionImp::processParameters(ExecState *exec, const List &args)
458{
459 Object variable = exec->context().imp()->variableObject();
460
461#ifdef KJS_VERBOSE
462 fprintf(stderr, "---------------------------------------------------\n"
463 "processing parameters for %s call\n",
464 name().isEmpty() ? "(internal)" : name().ascii());
465#endif
466
467 if (param) {
468 ListIterator it = args.begin();
469 Parameter *p = param;
470 while (p) {
471 if (it != args.end()) {
472#ifdef KJS_VERBOSE
473 fprintf(stderr, "setting parameter %s ", p->name.ascii());
474 printInfo(exec,"to", *it);
475#endif
476 variable.put(exec, p->name, *it);
477 it++;
478 } else
479 variable.put(exec, p->name, Undefined());
480 p = p->next;
481 }
482 }
483#ifdef KJS_VERBOSE
484 else {
485 for (int i = 0; i < args.size(); i++)
486 printInfo(exec,"setting argument", args[i]);
487 }
488#endif
489}
490
491void FunctionImp::processVarDecls(ExecState * /*exec*/)
492{
493}
494
495Value FunctionImp::get(ExecState *exec, const Identifier &propertyName) const
496{
497 // Find the arguments from the closest context.
498 if (propertyName == argumentsPropertyName) {
499// delme
500 ContextImp *context = exec->context().imp();
501// fixme
502// ContextImp *context = exec->_context;
503 while (context) {
504 if (context->function() == this)
505 return static_cast<ActivationImp *>
506 (context->activationObject())->get(exec, propertyName);
507 context = context->callingContext();
508 }
509 return Null();
510 }
511
512 // Compute length of parameters.
513 if (propertyName == lengthPropertyName) {
514 const Parameter * p = param;
515 int count = 0;
516 while (p) {
517 ++count;
518 p = p->next;
519 }
520 return Number(count);
521 }
522
523 if (propertyName == callerPropertyName) {
524 ContextImp *context = exec->context().imp();
525 while (context) {
526 if (context->function() == this) {
527 ContextImp *cc = context->callingContext();
528 if (cc && cc->function())
529 return Value(cc->function());
530 else
531 return Null();
532 }
533 context = context->callingContext();
534 }
535 return Null();
536 }
537
538 return InternalFunctionImp::get(exec, propertyName);
539}
540
541void FunctionImp::put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr)
542{
543 if (propertyName == argumentsPropertyName || propertyName == lengthPropertyName)
544 return;
545 InternalFunctionImp::put(exec, propertyName, value, attr);
546}
547
548bool FunctionImp::hasProperty(ExecState *exec, const Identifier &propertyName) const
549{
550 if (propertyName == argumentsPropertyName || propertyName == lengthPropertyName)
551 return true;
552 return InternalFunctionImp::hasProperty(exec, propertyName);
553}
554
555bool FunctionImp::deleteProperty(ExecState *exec, const Identifier &propertyName)
556{
557 if (propertyName == argumentsPropertyName || propertyName == lengthPropertyName)
558 return false;
559 return InternalFunctionImp::deleteProperty(exec, propertyName);
560}
561
562// ------------------------------ DeclaredFunctionImp --------------------------
563
564// ### is "Function" correct here?
565const ClassInfo DeclaredFunctionImp::info = {"Function", &FunctionImp::info, 0, 0};
566
567DeclaredFunctionImp::DeclaredFunctionImp(ExecState *exec, const Identifier &n,
568 FunctionBodyNode *b, const ScopeChain &sc)
569 : FunctionImp(exec,n), body(b)
570{
571 Value protect(this);
572 body->ref();
573 setScope(sc);
574 line0 = body->firstLine();
575 line1 = body->lastLine();
576 sid = body->sourceId();
577}
578
579DeclaredFunctionImp::~DeclaredFunctionImp()
580{
581 if ( body->deref() )
582 delete body;
583}
584
585bool DeclaredFunctionImp::implementsConstruct() const
586{
587 return true;
588}
589
590// ECMA 13.2.2 [[Construct]]
591Object DeclaredFunctionImp::construct(ExecState *exec, const List &args)
592{
593 Object proto;
594 Value p = get(exec,prototypePropertyName);
595 if (p.type() == ObjectType)
596 proto = Object(static_cast<ObjectImp*>(p.imp()));
597 else
598 proto = exec->lexicalInterpreter()->builtinObjectPrototype();
599
600 Object obj(new ObjectImp(proto));
601
602 Value res = call(exec,obj,args);
603
604 if (res.type() == ObjectType)
605 return Object::dynamicCast(res);
606 else
607 return obj;
608}
609
610Completion DeclaredFunctionImp::execute(ExecState *exec)
611{
612 Completion result = body->execute(exec);
613
614 if (result.complType() == Throw || result.complType() == ReturnValue)
615 return result;
616 return Completion(Normal, Undefined()); // TODO: or ReturnValue ?
617}
618
619void DeclaredFunctionImp::processVarDecls(ExecState *exec)
620{
621 body->processVarDecls(exec);
622}
623
624// ------------------------------- ShadowImp -----------------------------------
625
626namespace KJS {
627
628// Acts as a placeholder value to indicate that the actual value is kept
629// in the activation object
630class ShadowImp : public ObjectImp {
631public:
632 ShadowImp(ObjectImp *_obj, Identifier _prop) : obj(_obj), prop(_prop) {}
633 virtual void mark();
634
635 virtual const ClassInfo *classInfo() const { return &info; }
636 static const ClassInfo info;
637
638 ObjectImp *obj;
639 Identifier prop;
640};
641
642/*KDE_NOEXPORT*/ const ClassInfo ShadowImp::info = {"Shadow", 0, 0, 0};
643
644void ShadowImp::mark()
645{
646 ObjectImp::mark();
647 if (!obj->marked())
648 obj->mark();
649}
650
651}
652
653// ------------------------------ ArgumentsImp ---------------------------------
654
655const ClassInfo ArgumentsImp::info = {"Arguments", 0, 0, 0};
656
657// ECMA 10.1.8
658ArgumentsImp::ArgumentsImp(ExecState *exec, FunctionImp *func, const List &args,
659 ActivationImp *act)
660 : ObjectImp(exec->lexicalInterpreter()->builtinObjectPrototype()), activation(act)
661{
662 Value protect(this);
663 putDirect(calleePropertyName, func, DontEnum);
664 putDirect(lengthPropertyName, args.size(), DontEnum);
665 if (!args.isEmpty()) {
666 ListIterator arg = args.begin();
667 for (int i = 0; arg != args.end(); arg++, i++) {
668 Identifier prop = func->parameterProperty(i);
669 if (!prop.isEmpty()) {
670 Object shadow(new ShadowImp(act,prop));
671 ObjectImp::put(exec,Identifier::from(i), shadow, DontEnum);
672 }
673 else {
674 ObjectImp::put(exec,Identifier::from(i), *arg, DontEnum);
675 }
676 }
677 }
678}
679
680void ArgumentsImp::mark()
681{
682 ObjectImp::mark();
683 if (!activation->marked())
684 activation->mark();
685}
686
687Value ArgumentsImp::get(ExecState *exec, const Identifier &propertyName) const
688{
689 Value val = ObjectImp::get(exec,propertyName);
690 assert(SimpleNumber::is(val.imp()) || !val.imp()->isDestroyed());
691 Object obj = Object::dynamicCast(val);
692 if (obj.isValid() && obj.inherits(&ShadowImp::info)) {
693 ShadowImp *shadow = static_cast<ShadowImp*>(val.imp());
694 return activation->get(exec,shadow->prop);
695 }
696 else {
697 return val;
698 }
699}
700
701void ArgumentsImp::put(ExecState *exec, const Identifier &propertyName,
702 const Value &value, int attr)
703{
704 Value val = ObjectImp::get(exec,propertyName);
705 Object obj = Object::dynamicCast(val);
706 if (obj.isValid() && obj.inherits(&ShadowImp::info)) {
707 ShadowImp *shadow = static_cast<ShadowImp*>(val.imp());
708 activation->put(exec,shadow->prop,value,attr);
709 }
710 else {
711 ObjectImp::put(exec,propertyName,value,attr);
712 }
713}
714
715// ------------------------------ ActivationImp --------------------------------
716
717const ClassInfo ActivationImp::info = {"Activation", 0, 0, 0};
718
719// ECMA 10.1.6
720ActivationImp::ActivationImp(FunctionImp *function, const List &arguments)
721 : _function(function), _arguments(true), _argumentsObject(0)
722{
723 _arguments = arguments.copy();
724 // FIXME: Do we need to support enumerating the arguments property?
725}
726
727Value ActivationImp::get(ExecState *exec, const Identifier &propertyName) const
728{
729 if (propertyName == argumentsPropertyName) {
730 // check for locally declared arguments property
731 ValueImp *v = getDirect(propertyName);
732 if (v)
733 return Value(v);
734
735 // default: return builtin arguments array
736 if (!_argumentsObject)
737 _argumentsObject = new ArgumentsImp(exec, _function, _arguments, const_cast<ActivationImp*>(this));
738 return Value(_argumentsObject);
739 }
740 return ObjectImp::get(exec, propertyName);
741}
742
743bool ActivationImp::hasProperty(ExecState *exec, const Identifier &propertyName) const
744{
745 if (propertyName == argumentsPropertyName)
746 return true;
747 return ObjectImp::hasProperty(exec, propertyName);
748}
749
750bool ActivationImp::deleteProperty(ExecState *exec, const Identifier &propertyName)
751{
752 if (propertyName == argumentsPropertyName)
753 return false;
754 return ObjectImp::deleteProperty(exec, propertyName);
755}
756
757void ActivationImp::mark()
758{
759 ObjectImp::mark();
760 if (_function && !_function->marked())
761 _function->mark();
762 _arguments.mark();
763 if (_argumentsObject && !_argumentsObject->marked())
764 _argumentsObject->mark();
765}
766
767// ------------------------------ GlobalFunc -----------------------------------
768
769
770GlobalFuncImp::GlobalFuncImp(ExecState * /*exec*/, FunctionPrototypeImp *funcProto,
771 int i, int len, const Identifier &_ident)
772 : InternalFunctionImp(funcProto), id(i)
773{
774 Value protect(this);
775 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
776 ident = _ident;
777}
778
779CodeType GlobalFuncImp::codeType() const
780{
781 return id == Eval ? EvalCode : codeType();
782}
783
784bool GlobalFuncImp::implementsCall() const
785{
786 return true;
787}
788
789Value GlobalFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
790{
791 Value res;
792
793 static const char do_not_escape[] =
794 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
795 "abcdefghijklmnopqrstuvwxyz"
796 "0123456789"
797 "*+-./@_";
798
799 switch (id) {
800 case Eval: { // eval()
801 Value x = args[0];
802 if (x.type() != StringType)
803 return x;
804 else {
805 UString s = x.toString(exec);
806
807 int errLine;
808 UString errMsg;
809#ifdef KJS_VERBOSE
810 fprintf(stderr, "eval(): %s\n", s.ascii());
811#endif
812 SourceCode *source;
813 FunctionBodyNode *progNode = Parser::parse(s.data(),s.size(),&source,&errLine,&errMsg);
814
815 // notify debugger that source has been parsed
816 Debugger *dbg = exec->interpreter()->imp()->debugger();
817 if (dbg) {
818 bool cont = dbg->sourceParsed(exec,source->sid,s,errLine);
819 if (!cont) {
820 source->deref();
821 dbg->imp()->abort();
822 if (progNode)
823 delete progNode;
824 return Undefined();
825 }
826 }
827
828 exec->interpreter()->imp()->addSourceCode(source);
829
830 // no program node means a syntax occurred
831 if (!progNode) {
832 Object err = Error::create(exec,SyntaxError,errMsg.ascii(),errLine);
833 err.put(exec,"sid",Number(source->sid));
834 exec->setException(err);
835 source->deref();
836 return err;
837 }
838
839 source->deref();
840 progNode->ref();
841
842 // enter a new execution context
843 ContextImp ctx(exec->dynamicInterpreter()->globalObject(),
844 exec->dynamicInterpreter()->imp(),
845 thisObj,
846 source->sid,
847 EvalCode,
848 exec->context().imp());
849
850 ExecState newExec(exec->dynamicInterpreter(), &ctx);
851 newExec.setException(exec->exception()); // could be null
852
853 ctx.setLines(progNode->firstLine(),progNode->firstLine());
854 if (dbg) {
855 if (!dbg->enterContext(&newExec)) {
856 // debugger requested we stop execution
857 dbg->imp()->abort();
858
859 if (progNode->deref())
860 delete progNode;
861 return Undefined();
862 }
863 }
864
865 // execute the code
866 progNode->processVarDecls(&newExec);
867 Completion c = progNode->execute(&newExec);
868
869 res = Undefined();
870
871 ctx.setLines(progNode->lastLine(),progNode->lastLine());
872 if (dbg && !dbg->exitContext(&newExec,c))
873 // debugger requested we stop execution
874 dbg->imp()->abort();
875 else if (newExec.hadException()) // propagate back to parent context
876 exec->setException(newExec.exception());
877 else if (c.complType() == Throw)
878 exec->setException(c.value());
879 else if (c.isValueCompletion())
880 res = c.value();
881
882 if (progNode->deref())
883 delete progNode;
884
885 return res;
886 }
887 break;
888 }
889 case ParseInt: { // ECMA 15.1.2.2
890 CString cstr = args[0].toString(exec).cstring();
891 const char* startptr = cstr.c_str();
892 while ( *startptr && isspace( *startptr ) ) // first, skip leading spaces
893 ++startptr;
894
895 int base = 0;
896 if (args.size() > 1)
897 base = args[1].toInt32(exec);
898
899 double sign = 1;
900 if (*startptr == '-') {
901 sign = -1;
902 startptr++;
903 }
904 else if (*startptr == '+') {
905 sign = 1;
906 startptr++;
907 }
908
909 bool leading0 = false;
910 if ((base == 0 || base == 16) &&
911 (*startptr == '0' && (startptr[1] == 'x' || startptr[1] == 'X'))) {
912 startptr += 2;
913 base = 16;
914 }
915 else if (base == 0 && *startptr == '0') {
916 base = 8;
917 leading0 = true;
918 startptr++;
919 }
920 else if (base == 0) {
921 base = 10;
922 }
923
924 if (base < 2 || base > 36) {
925 res = Number(NaN);
926 }
927 else {
928 long double val = 0;
929 int index = 0;
930 for (; *startptr; startptr++) {
931 int thisval = -1;
932 if (*startptr >= '0' && *startptr <= '9')
933 thisval = *startptr - '0';
934 else if (*startptr >= 'a' && *startptr <= 'z')
935 thisval = 10 + *startptr - 'a';
936 else if (*startptr >= 'A' && *startptr <= 'Z')
937 thisval = 10 + *startptr - 'A';
938
939 if (thisval < 0 || thisval >= base)
940 break;
941
942 val *= base;
943 val += thisval;
944 index++;
945 }
946
947 if (index == 0 && !leading0)
948 res = Number(NaN);
949 else
950 res = Number(double(val)*sign);
951 }
952 break;
953 }
954 case ParseFloat: {
955 UString str = args[0].toString(exec);
956 // don't allow hex numbers here
957 bool isHex = false;
958 if (str.is8Bit()) {
959 const char *c = str.ascii();
960 while (isspace(*c))
961 c++;
962 isHex = (c[0] == '0' && (c[1] == 'x' || c[1] == 'X'));
963 }
964 if (isHex)
965 res = Number(0);
966 else
967 res = Number(str.toDouble( true /*tolerant*/, false ));
968 }
969 break;
970 case IsNaN:
971 res = Boolean(isNaN(args[0].toNumber(exec)));
972 break;
973 case IsFinite: {
974 double n = args[0].toNumber(exec);
975 res = Boolean(!isNaN(n) && !isInf(n));
976 break;
977 }
978 case DecodeURI:
979 res = String(decodeURI(exec,args[0].toString(exec),uriReserved+"#"));
980 break;
981 case DecodeURIComponent:
982 res = String(decodeURI(exec,args[0].toString(exec),""));
983 break;
984 case EncodeURI:
985 res = String(encodeURI(exec,args[0].toString(exec),uriReserved+uriUnescaped+"#"));
986 break;
987 case EncodeURIComponent:
988 res = String(encodeURI(exec,args[0].toString(exec),uriUnescaped));
989 break;
990 case Escape: {
991 UString r = "", s, str = args[0].toString(exec);
992 const UChar *c = str.data();
993 for (int k = 0; k < str.size(); k++, c++) {
994 int u = c->uc;
995 if (u > 255) {
996 char tmp[7];
997 sprintf(tmp, "%%u%04X", u);
998 s = UString(tmp);
999 } else if (u != 0 && strchr(do_not_escape, (char)u)) {
1000 s = UString(c, 1);
1001 } else {
1002 char tmp[4];
1003 sprintf(tmp, "%%%02X", u);
1004 s = UString(tmp);
1005 }
1006 r += s;
1007 }
1008 res = String(r);
1009 break;
1010 }
1011 case UnEscape: {
1012 UString s = "", str = args[0].toString(exec);
1013 int k = 0, len = str.size();
1014 while (k < len) {
1015 const UChar *c = str.data() + k;
1016 UChar u;
1017 if (*c == UChar('%') && k <= len - 6 && *(c+1) == UChar('u')) {
1018 if (Lexer::isHexDigit((c+2)->uc) && Lexer::isHexDigit((c+3)->uc) &&
1019 Lexer::isHexDigit((c+4)->uc) && Lexer::isHexDigit((c+5)->uc)) {
1020 u = Lexer::convertUnicode((c+2)->uc, (c+3)->uc,
1021 (c+4)->uc, (c+5)->uc);
1022 c = &u;
1023 k += 5;
1024 }
1025 } else if (*c == UChar('%') && k <= len - 3 &&
1026 Lexer::isHexDigit((c+1)->uc) && Lexer::isHexDigit((c+2)->uc)) {
1027 u = UChar(Lexer::convertHex((c+1)->uc, (c+2)->uc));
1028 c = &u;
1029 k += 2;
1030 }
1031 k++;
1032 s += UString(c, 1);
1033 }
1034 res = String(s);
1035 break;
1036 }
1037 case KJSPrint:
1038#ifndef NDEBUG
1039 puts(args[0].toString(exec).ascii());
1040#endif
1041 break;
1042 }
1043
1044 return res;
1045}
KJS::Boolean
Represents an primitive Boolean value.
Definition: value.h:316
KJS::CString
8 bit char based string class
Definition: ustring.h:165
KJS::Completion
Completion objects are used to convey the return status and value from functions.
Definition: completion.h:48
KJS::ContextImp
Execution context.
Definition: context.h:34
KJS::ExecState
Represents the current state of script execution.
Definition: interpreter.h:438
KJS::ExecState::context
Context context() const
Returns the execution context associated with this execution state.
Definition: interpreter.h:470
KJS::ExecState::dynamicInterpreter
Interpreter * dynamicInterpreter() const
Returns the interpreter associated with this execution state.
Definition: interpreter.h:452
KJS::ExecState::lexicalInterpreter
Interpreter * lexicalInterpreter() const
Returns the interpreter associated with the current scope's global object.
Definition: interpreter.cpp:394
KJS::FunctionImp
Implementation class for functions implemented in JS.
Definition: internal.h:389
KJS::FunctionPrototypeImp
The initial value of Function.prototype (and thus all objects created with the Function constructor)
Definition: function_object.h:34
KJS::Identifier
Represents an Identifier for a Javascript object.
Definition: identifier.h:32
KJS::Identifier::null
static const Identifier & null()
Creates an empty Identifier.
Definition: identifier.cpp:302
KJS::Identifier::isEmpty
bool isEmpty() const
Returns that the identifiers string is set, but is empty.
Definition: identifier.h:82
KJS::InternalFunctionImp
Base class for all function objects.
Definition: function.h:40
KJS::Interpreter::builtinObjectPrototype
Object builtinObjectPrototype() const
Returns the builtin "Object.prototype" object.
Definition: interpreter.cpp:218
KJS::Interpreter::globalObject
Object & globalObject() const
Returns the object that is used as the global object during all script execution performed by this in...
Definition: interpreter.cpp:128
KJS::ListIterator
Iterator for KJS::List objects.
Definition: list.h:138
KJS::List
Native list type.
Definition: list.h:48
KJS::List::isEmpty
bool isEmpty() const
Definition: list.h:86
KJS::List::begin
ListIterator begin() const
Definition: list.h:186
KJS::List::copy
List copy() const
Make a copy of the list.
Definition: list.cpp:281
KJS::List::size
int size() const
Definition: list.h:90
KJS::List::end
ListIterator end() const
Definition: list.h:187
KJS::Null
Represents an primitive Null value.
Definition: value.h:294
KJS::Number
Represents an primitive Number value.
Definition: value.h:367
KJS::Object
Represents an Object.
Definition: object.h:81
KJS::Object::put
void put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr=None)
Sets the specified property.
Definition: object.h:669
KJS::ScopeChain
A scope chain object.
Definition: scope_chain.h:47
KJS::String
Represents an primitive String value.
Definition: value.h:340
KJS::UString
Unicode string class.
Definition: ustring.h:189
KJS::UString::is8Bit
bool is8Bit() const
Use this if you want to make sure that this string is a plain ASCII string.
Definition: ustring.cpp:549
KJS::UString::toDouble
double toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const
Attempts an conversion to a number.
Definition: ustring.cpp:607
KJS::UString::find
int find(const UString &f, int pos=0) const
Definition: ustring.cpp:798
KJS::UString::isEmpty
bool isEmpty() const
Definition: ustring.h:347
KJS::UString::ascii
char * ascii() const
Convert the Unicode string to plain ASCII chars chopping of any higher bytes.
Definition: ustring.cpp:485
KJS::UString::size
int size() const
Definition: ustring.h:359
KJS::UString::data
const UChar * data() const
Definition: ustring.h:339
KJS::Undefined
Represents an primitive Undefined value.
Definition: value.h:269
KJS::ValueImp
ValueImp is the base type for all primitives (Undefined, Null, Boolean, String, Number) and objects i...
Definition: value.h:78
KJS::Value
Value objects are act as wrappers ("smart pointers") around ValueImp objects and their descendents.
Definition: value.h:167
KJS::Value::toString
UString toString(ExecState *exec) const
Performs the ToString type conversion operation on this value (ECMA 9.8)
Definition: value.h:246
KJS::Value::isValid
bool isValid() const
Returns whether or not this is a valid value.
Definition: value.h:181
KJS::Value::type
Type type() const
Returns the type of value.
Definition: value.h:195
TDEStdAccel::next
const TDEShortcut & next()
TDEStdAccel::name
TQString name(StdAccel id)
KJS::ClassInfo
Class Information.
Definition: object.h:58
KJS::UChar
Unicode character.
Definition: ustring.h:51

kjs

Skip menu "kjs"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kjs

Skip menu "kjs"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kjs by doxygen 1.9.4
This website is maintained by Timothy Pearson.