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

kjs

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

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.8.1.2
This website is maintained by Timothy Pearson.