• 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 
42 using namespace KJS;
43 
44 // ------------------------- URI handling functions ---------------------------
45 
46 // ECMA 15.1.3
47 UString 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 
141 static 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 
165 UString 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 
308 static UString uriReserved = ";/?:@&=+$,";
309 static UString uriAlpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
310 static UString DecimalDigit = "0123456789";
311 static UString uriMark = "-_.!~*'()";
312 static UString uriUnescaped = uriAlpha+DecimalDigit+uriMark;
313 
314 // ----------------------------- FunctionImp ----------------------------------
315 
316 const ClassInfo FunctionImp::info = {"Function", &InternalFunctionImp::info, 0, 0};
317 
318 namespace 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 
328 FunctionImp::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 
337 FunctionImp::~FunctionImp()
338 {
339  delete param;
340 }
341 
342 bool FunctionImp::implementsCall() const
343 {
344  return true;
345 }
346 
347 Value 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 
412 void 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 
421 Identifier 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 
441 UString 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
457 void 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 
491 void FunctionImp::processVarDecls(ExecState * /*exec*/)
492 {
493 }
494 
495 Value 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 
541 void 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 
548 bool 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 
555 bool 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?
565 const ClassInfo DeclaredFunctionImp::info = {"Function", &FunctionImp::info, 0, 0};
566 
567 DeclaredFunctionImp::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 
579 DeclaredFunctionImp::~DeclaredFunctionImp()
580 {
581  if ( body->deref() )
582  delete body;
583 }
584 
585 bool DeclaredFunctionImp::implementsConstruct() const
586 {
587  return true;
588 }
589 
590 // ECMA 13.2.2 [[Construct]]
591 Object 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 
610 Completion 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 
619 void DeclaredFunctionImp::processVarDecls(ExecState *exec)
620 {
621  body->processVarDecls(exec);
622 }
623 
624 // ------------------------------- ShadowImp -----------------------------------
625 
626 namespace KJS {
627 
628 // Acts as a placeholder value to indicate that the actual value is kept
629 // in the activation object
630 class ShadowImp : public ObjectImp {
631 public:
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 
644 void ShadowImp::mark()
645 {
646  ObjectImp::mark();
647  if (!obj->marked())
648  obj->mark();
649 }
650 
651 }
652 
653 // ------------------------------ ArgumentsImp ---------------------------------
654 
655 const ClassInfo ArgumentsImp::info = {"Arguments", 0, 0, 0};
656 
657 // ECMA 10.1.8
658 ArgumentsImp::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 
680 void ArgumentsImp::mark()
681 {
682  ObjectImp::mark();
683  if (!activation->marked())
684  activation->mark();
685 }
686 
687 Value 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 
701 void 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 
717 const ClassInfo ActivationImp::info = {"Activation", 0, 0, 0};
718 
719 // ECMA 10.1.6
720 ActivationImp::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 
727 Value 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 
743 bool ActivationImp::hasProperty(ExecState *exec, const Identifier &propertyName) const
744 {
745  if (propertyName == argumentsPropertyName)
746  return true;
747  return ObjectImp::hasProperty(exec, propertyName);
748 }
749 
750 bool ActivationImp::deleteProperty(ExecState *exec, const Identifier &propertyName)
751 {
752  if (propertyName == argumentsPropertyName)
753  return false;
754  return ObjectImp::deleteProperty(exec, propertyName);
755 }
756 
757 void 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 
770 GlobalFuncImp::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 
779 CodeType GlobalFuncImp::codeType() const
780 {
781  return id == Eval ? EvalCode : codeType();
782 }
783 
784 bool GlobalFuncImp::implementsCall() const
785 {
786  return true;
787 }
788 
789 Value 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::Error::create
static Object create(ExecState *exec, ErrorType errtype=GeneralError, const char *message=0, int lineno=-1, int sourceId=-1)
Factory method for error objects.
Definition: object.cpp:503
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::lexicalInterpreter
Interpreter * lexicalInterpreter() const
Returns the interpreter associated with the current scope's global object.
Definition: interpreter.cpp:394
KJS::ExecState::dynamicInterpreter
Interpreter * dynamicInterpreter() const
Returns the interpreter associated with this execution state.
Definition: interpreter.h:452
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::data
const UChar * data() const
Definition: ustring.h:339
KJS::UString::size
int size() const
Definition: ustring.h:359
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.1
This website is maintained by Timothy Pearson.