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

kjs

  • kjs
internal.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 Peter Kelly (pmk@post.com)
5  * Copyright (C) 2004 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 <stdio.h>
25 #include <math.h>
26 #include <assert.h>
27 
28 #include "array_object.h"
29 #include "bool_object.h"
30 #include "collector.h"
31 #include "context.h"
32 #include "date_object.h"
33 #include "debugger.h"
34 #include "error_object.h"
35 #include "function_object.h"
36 #include "internal.h"
37 #include "lexer.h"
38 #include "math_object.h"
39 #include "nodes.h"
40 #include "number_object.h"
41 #include "object.h"
42 #include "object_object.h"
43 #include "operations.h"
44 #include "regexp_object.h"
45 #include "string_object.h"
46 
47 #define I18N_NOOP(s) s
48 
49 extern int kjsyyparse();
50 
51 using namespace KJS;
52 
53 namespace KJS {
54  /* work around some strict alignment requirements
55  for double variables on some architectures (e.g. PA-RISC) */
56  typedef union { unsigned char b[8]; double d; } kjs_double_t;
57 
58 #ifdef WORDS_BIGENDIAN
59  static const kjs_double_t NaN_Bytes = { { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 } };
60  static const kjs_double_t Inf_Bytes = { { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 } };
61 #elif defined(arm)
62  static const kjs_double_t NaN_Bytes = { { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 } };
63  static const kjs_double_t Inf_Bytes = { { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 } };
64 #else
65  static const kjs_double_t NaN_Bytes = { { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f } };
66  static const kjs_double_t Inf_Bytes = { { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f } };
67 #endif
68 
69  const double NaN = NaN_Bytes.d;
70  const double Inf = Inf_Bytes.d;
71 }
72 
73 #ifdef KJS_THREADSUPPORT
74 static pthread_once_t interpreterLockOnce = PTHREAD_ONCE_INIT;
75 static pthread_mutex_t interpreterLock;
76 static int interpreterLockCount = 0;
77 
78 static void initializeInterpreterLock()
79 {
80  pthread_mutexattr_t attr;
81 
82  pthread_mutexattr_init(&attr);
83  pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
84 
85  pthread_mutex_init(&interpreterLock, &attr);
86 }
87 #endif
88 
89 static inline void lockInterpreter()
90 {
91 #ifdef KJS_THREADSUPPORT
92  pthread_once(&interpreterLockOnce, initializeInterpreterLock);
93  pthread_mutex_lock(&interpreterLock);
94  interpreterLockCount++;
95 #endif
96 }
97 
98 static inline void unlockInterpreter()
99 {
100 #ifdef KJS_THREADSUPPORT
101  interpreterLockCount--;
102  pthread_mutex_unlock(&interpreterLock);
103 #endif
104 }
105 
106 
107 
108 // ------------------------------ UndefinedImp ---------------------------------
109 
110 UndefinedImp *UndefinedImp::staticUndefined = 0;
111 
112 Value UndefinedImp::toPrimitive(ExecState* /*exec*/, Type) const
113 {
114  return Value((ValueImp*)this);
115 }
116 
117 bool UndefinedImp::toBoolean(ExecState* /*exec*/) const
118 {
119  return false;
120 }
121 
122 double UndefinedImp::toNumber(ExecState* /*exec*/) const
123 {
124  return NaN;
125 }
126 
127 UString UndefinedImp::toString(ExecState* /*exec*/) const
128 {
129  return "undefined";
130 }
131 
132 Object UndefinedImp::toObject(ExecState *exec) const
133 {
134  Object err = Error::create(exec, TypeError, I18N_NOOP("Undefined value"));
135  exec->setException(err);
136  return err;
137 }
138 
139 // ------------------------------ NullImp --------------------------------------
140 
141 NullImp *NullImp::staticNull = 0;
142 
143 Value NullImp::toPrimitive(ExecState* /*exec*/, Type) const
144 {
145  return Value((ValueImp*)this);
146 }
147 
148 bool NullImp::toBoolean(ExecState* /*exec*/) const
149 {
150  return false;
151 }
152 
153 double NullImp::toNumber(ExecState* /*exec*/) const
154 {
155  return 0.0;
156 }
157 
158 UString NullImp::toString(ExecState* /*exec*/) const
159 {
160  return "null";
161 }
162 
163 Object NullImp::toObject(ExecState *exec) const
164 {
165  Object err = Error::create(exec, TypeError, I18N_NOOP("Null value"));
166  exec->setException(err);
167  return err;
168 }
169 
170 // ------------------------------ BooleanImp -----------------------------------
171 
172 BooleanImp* BooleanImp::staticTrue = 0;
173 BooleanImp* BooleanImp::staticFalse = 0;
174 
175 Value BooleanImp::toPrimitive(ExecState* /*exec*/, Type) const
176 {
177  return Value((ValueImp*)this);
178 }
179 
180 bool BooleanImp::toBoolean(ExecState* /*exec*/) const
181 {
182  return val;
183 }
184 
185 double BooleanImp::toNumber(ExecState* /*exec*/) const
186 {
187  return val ? 1.0 : 0.0;
188 }
189 
190 UString BooleanImp::toString(ExecState* /*exec*/) const
191 {
192  return val ? "true" : "false";
193 }
194 
195 Object BooleanImp::toObject(ExecState *exec) const
196 {
197  List args;
198  args.append(const_cast<BooleanImp*>(this));
199  return Object::dynamicCast(exec->lexicalInterpreter()->builtinBoolean().construct(exec,args));
200 }
201 
202 // ------------------------------ StringImp ------------------------------------
203 
204 Value StringImp::toPrimitive(ExecState* /*exec*/, Type) const
205 {
206  return Value((ValueImp*)this);
207 }
208 
209 bool StringImp::toBoolean(ExecState* /*exec*/) const
210 {
211  return (val.size() > 0);
212 }
213 
214 double StringImp::toNumber(ExecState* /*exec*/) const
215 {
216  return val.toDouble();
217 }
218 
219 UString StringImp::toString(ExecState* /*exec*/) const
220 {
221  return val;
222 }
223 
224 Object StringImp::toObject(ExecState *exec) const
225 {
226  List args;
227  args.append(const_cast<StringImp*>(this));
228  return Object(static_cast<ObjectImp *>(exec->lexicalInterpreter()->builtinString().construct(exec, args).imp()));
229 }
230 
231 // ------------------------------ NumberImp ------------------------------------
232 
233 NumberImp *NumberImp::staticNaN;
234 
235 ValueImp *NumberImp::create(int i)
236 {
237  if (SimpleNumber::fits(i))
238  return SimpleNumber::make(i);
239  NumberImp *imp = new NumberImp(static_cast<double>(i));
240  imp->setGcAllowedFast();
241  return imp;
242 }
243 
244 ValueImp *NumberImp::create(double d)
245 {
246  if (SimpleNumber::fits(d))
247  return SimpleNumber::make((int)d);
248  if (isNaN(d))
249  return staticNaN;
250  NumberImp *imp = new NumberImp(d);
251  imp->setGcAllowedFast();
252  return imp;
253 }
254 
255 Value NumberImp::toPrimitive(ExecState *, Type) const
256 {
257  return Number((NumberImp*)this);
258 }
259 
260 bool NumberImp::toBoolean(ExecState *) const
261 {
262  return !((val == 0) /* || (iVal() == N0) */ || isNaN(val));
263 }
264 
265 double NumberImp::toNumber(ExecState *) const
266 {
267  return val;
268 }
269 
270 UString NumberImp::toString(ExecState *) const
271 {
272  if (val == 0.0) // +0.0 or -0.0
273  return "0";
274  return UString::from(val);
275 }
276 
277 Object NumberImp::toObject(ExecState *exec) const
278 {
279  List args;
280  args.append(const_cast<NumberImp*>(this));
281  return Object::dynamicCast(exec->lexicalInterpreter()->builtinNumber().construct(exec,args));
282 }
283 
284 bool NumberImp::toUInt32(unsigned& uint32) const
285 {
286  uint32 = (unsigned)val;
287  return (double)uint32 == val;
288 }
289 
290 double SimpleNumber::negZero = -0.0;
291 
292 // ------------------------------ LabelStack -----------------------------------
293 
294 LabelStack::LabelStack(const LabelStack &other)
295 {
296  tos = 0;
297  *this = other;
298 }
299 
300 LabelStack &LabelStack::operator=(const LabelStack &other)
301 {
302  clear();
303  tos = 0;
304  StackElem *cur = 0;
305  StackElem *se = other.tos;
306  while (se) {
307  StackElem *newPrev = new StackElem;
308  newPrev->prev = 0;
309  newPrev->id = se->id;
310  if (cur)
311  cur->prev = newPrev;
312  else
313  tos = newPrev;
314  cur = newPrev;
315  se = se->prev;
316  }
317  return *this;
318 }
319 
320 bool LabelStack::push(const Identifier &id)
321 {
322  if (id.isEmpty() || contains(id))
323  return false;
324 
325  StackElem *newtos = new StackElem;
326  newtos->id = id;
327  newtos->prev = tos;
328  tos = newtos;
329  return true;
330 }
331 
332 bool LabelStack::contains(const Identifier &id) const
333 {
334  if (id.isEmpty())
335  return true;
336 
337  for (StackElem *curr = tos; curr; curr = curr->prev)
338  if (curr->id == id)
339  return true;
340 
341  return false;
342 }
343 
344 void LabelStack::pop()
345 {
346  if (tos) {
347  StackElem *prev = tos->prev;
348  delete tos;
349  tos = prev;
350  }
351 }
352 
353 LabelStack::~LabelStack()
354 {
355  clear();
356 }
357 
358 void LabelStack::clear()
359 {
360  StackElem *prev;
361 
362  while (tos) {
363  prev = tos->prev;
364  delete tos;
365  tos = prev;
366  }
367 }
368 
369 // ------------------------------ ContextImp -----------------------------------
370 
371 
372 // ECMA 10.2
373 ContextImp::ContextImp(Object &glob, InterpreterImp *interpreter, Object &thisV, int _sourceId, CodeType type,
374  ContextImp *callingCon, FunctionImp *func, const List *args)
375  : _interpreter(interpreter), _function(func), _arguments(args)
376 {
377  m_codeType = type;
378  _callingContext = callingCon;
379  tryCatch = 0;
380 
381  sourceId = _sourceId;
382  line0 = 1;
383  line1 = 1;
384 
385  if (func && func->inherits(&DeclaredFunctionImp::info))
386  functionName = static_cast<DeclaredFunctionImp*>(func)->name();
387  else
388  functionName = Identifier::null();
389 
390  // create and initialize activation object (ECMA 10.1.6)
391  if (type == FunctionCode) {
392  activation = Object(new ActivationImp(func,*args));
393  variable = activation;
394  } else {
395  activation = Object();
396  variable = glob;
397  }
398 
399  // ECMA 10.2
400  switch(type) {
401  case EvalCode:
402  if (_callingContext) {
403  scope = _callingContext->scopeChain();
404 #ifndef KJS_PURE_ECMA
405  if (thisV.imp() != glob.imp())
406  scope.push(thisV.imp()); // for deprecated Object.prototype.eval()
407 #endif
408  variable = _callingContext->variableObject();
409  thisVal = _callingContext->thisValue();
410  break;
411  } // else same as GlobalCode
412  case GlobalCode:
413  scope.clear();
414  scope.push(glob.imp());
415 #ifndef KJS_PURE_ECMA
416  if (thisV.isValid())
417  thisVal = thisV;
418  else
419 #endif
420  thisVal = glob;
421  break;
422  case FunctionCode:
423  scope = func->scope();
424  scope.push(activation.imp());
425  variable = activation; // TODO: DontDelete ? (ECMA 10.2.3)
426  thisVal = thisV;
427  break;
428  }
429 
430  _interpreter->setContext(this);
431 }
432 
433 ContextImp::~ContextImp()
434 {
435  _interpreter->setContext(_callingContext);
436 }
437 
438 void ContextImp::mark()
439 {
440  for (ContextImp *context = this; context; context = context->_callingContext) {
441  context->scope.mark();
442  }
443 }
444 
445 bool ContextImp::inTryCatch() const
446 {
447  const ContextImp *c = this;
448  while (c && !c->tryCatch)
449  c = c->_callingContext;
450  return (c && c->tryCatch);
451 }
452 
453 // ---------------------------- SourceCode -------------------------------------
454 
455 void SourceCode::cleanup()
456 {
457  if (interpreter && interpreter->debugger())
458  interpreter->debugger()->sourceUnused(interpreter->globalExec(),sid);
459  if (interpreter)
460  interpreter->removeSourceCode(this);
461  delete this;
462 }
463 
464 // ------------------------------ Parser ---------------------------------------
465 
466 FunctionBodyNode *Parser::progNode = 0;
467 int Parser::sid = 0;
468 SourceCode *Parser::source = 0;
469 
470 FunctionBodyNode *Parser::parse(const UChar *code, unsigned int length, SourceCode **src,
471  int *errLine, UString *errMsg)
472 {
473  if (errLine)
474  *errLine = -1;
475  if (errMsg)
476  *errMsg = 0;
477 
478  Lexer::curr()->setCode(code, length);
479  progNode = 0;
480  sid++;
481 
482  source = new SourceCode(sid);
483  source->ref();
484  *src = source;
485 
486  // Enable this (and the #define YYDEBUG in grammar.y) to debug a parse error
487  //extern int kjsyydebug;
488  //kjsyydebug=1;
489  int parseError = kjsyyparse();
490  if (Lexer::curr()->hadError())
491  parseError = 1;
492  Lexer::curr()->doneParsing();
493  FunctionBodyNode *prog = progNode;
494  progNode = 0;
495  //sid = -1;
496  source = 0;
497 
498  if (parseError) {
499  int eline = Lexer::curr()->lineNo();
500  if (errLine)
501  *errLine = eline;
502  if (errMsg)
503  *errMsg = "Parse error at line " + UString::from(eline);
504 #ifdef KJS_VERBOSE
505  fprintf( stderr, "[kjs-internal] %s\n", UString(code,length).ascii() );
506 #endif
507 #ifndef NDEBUG
508  fprintf( stderr, "[kjs-internal] KJS: JavaScript parse error at line %d.\n", eline);
509 #endif
510  delete prog;
511  return 0;
512  }
513 #ifdef KJS_VERBOSE
514  fprintf( stderr, "[kjs-internal] %s\n", prog->toCode().ascii() );
515 #endif
516 
517  return prog;
518 }
519 
520 // ------------------------------ InterpreterImp -------------------------------
521 
522 InterpreterImp* InterpreterImp::s_hook = 0L;
523 
524 void InterpreterImp::globalInit()
525 {
526  //fprintf( stderr, "[kjs-internal] InterpreterImp::globalInit()\n" );
527  UndefinedImp::staticUndefined = new UndefinedImp();
528  UndefinedImp::staticUndefined->ref();
529  NullImp::staticNull = new NullImp();
530  NullImp::staticNull->ref();
531  BooleanImp::staticTrue = new BooleanImp(true);
532  BooleanImp::staticTrue->ref();
533  BooleanImp::staticFalse = new BooleanImp(false);
534  BooleanImp::staticFalse->ref();
535  NumberImp::staticNaN = new NumberImp(NaN);
536  NumberImp::staticNaN->ref();
537 }
538 
539 void InterpreterImp::globalClear()
540 {
541  //fprintf( stderr, "[kjs-internal] InterpreterImp::globalClear()\n" );
542  UndefinedImp::staticUndefined->deref();
543  UndefinedImp::staticUndefined->setGcAllowed();
544  UndefinedImp::staticUndefined = 0L;
545  NullImp::staticNull->deref();
546  NullImp::staticNull->setGcAllowed();
547  NullImp::staticNull = 0L;
548  BooleanImp::staticTrue->deref();
549  BooleanImp::staticTrue->setGcAllowed();
550  BooleanImp::staticTrue = 0L;
551  BooleanImp::staticFalse->deref();
552  BooleanImp::staticFalse->setGcAllowed();
553  BooleanImp::staticFalse = 0L;
554  NumberImp::staticNaN->deref();
555  NumberImp::staticNaN->setGcAllowed();
556  NumberImp::staticNaN = 0;
557 }
558 
559 InterpreterImp::InterpreterImp(Interpreter *interp, const Object &glob)
560  : m_interpreter(interp),
561  global(glob),
562  dbg(0),
563  m_compatMode(Interpreter::NativeMode),
564  _context(0),
565  recursion(0),
566  sources(0)
567 {
568  // add this interpreter to the global chain
569  // as a root set for garbage collection
570  lockInterpreter();
571  if (s_hook) {
572  prev = s_hook;
573  next = s_hook->next;
574  s_hook->next->prev = this;
575  s_hook->next = this;
576  } else {
577  // This is the first interpreter
578  s_hook = next = prev = this;
579  globalInit();
580  }
581  unlockInterpreter();
582 
583  globExec = new ExecState(m_interpreter,0);
584 
585  // initialize properties of the global object
586  initGlobalObject();
587 }
588 
589 void InterpreterImp::lock()
590 {
591  lockInterpreter();
592 }
593 
594 void InterpreterImp::unlock()
595 {
596  unlockInterpreter();
597 }
598 
599 void InterpreterImp::initGlobalObject()
600 {
601  // Contructor prototype objects (Object.prototype, Array.prototype etc)
602 
603  FunctionPrototypeImp *funcProto = new FunctionPrototypeImp(globExec);
604  b_FunctionPrototype = Object(funcProto);
605  ObjectPrototypeImp *objProto = new ObjectPrototypeImp(globExec,funcProto);
606  b_ObjectPrototype = Object(objProto);
607  funcProto->setPrototype(b_ObjectPrototype);
608 
609  ArrayPrototypeImp *arrayProto = new ArrayPrototypeImp(globExec,objProto);
610  b_ArrayPrototype = Object(arrayProto);
611  StringPrototypeImp *stringProto = new StringPrototypeImp(globExec,objProto);
612  b_StringPrototype = Object(stringProto);
613  BooleanPrototypeImp *booleanProto = new BooleanPrototypeImp(globExec,objProto,funcProto);
614  b_BooleanPrototype = Object(booleanProto);
615  NumberPrototypeImp *numberProto = new NumberPrototypeImp(globExec,objProto,funcProto);
616  b_NumberPrototype = Object(numberProto);
617  DatePrototypeImp *dateProto = new DatePrototypeImp(globExec,objProto);
618  b_DatePrototype = Object(dateProto);
619  RegExpPrototypeImp *regexpProto = new RegExpPrototypeImp(globExec,objProto,funcProto);
620  b_RegExpPrototype = Object(regexpProto);
621  ErrorPrototypeImp *errorProto = new ErrorPrototypeImp(globExec,objProto,funcProto);
622  b_ErrorPrototype = Object(errorProto);
623 
624  static_cast<ObjectImp*>(global.imp())->setPrototype(b_ObjectPrototype);
625 
626  // Constructors (Object, Array, etc.)
627 
628  b_Object = Object(new ObjectObjectImp(globExec, objProto, funcProto));
629  b_Function = Object(new FunctionObjectImp(globExec, funcProto));
630  b_Array = Object(new ArrayObjectImp(globExec, funcProto, arrayProto));
631  b_String = Object(new StringObjectImp(globExec, funcProto, stringProto));
632  b_Boolean = Object(new BooleanObjectImp(globExec, funcProto, booleanProto));
633  b_Number = Object(new NumberObjectImp(globExec, funcProto, numberProto));
634  b_Date = Object(new DateObjectImp(globExec, funcProto, dateProto));
635  b_RegExp = Object(new RegExpObjectImp(globExec, funcProto, regexpProto));
636  b_Error = Object(new ErrorObjectImp(globExec, funcProto, errorProto));
637 
638  // Error object prototypes
639  b_evalErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,EvalError,
640  "EvalError","EvalError"));
641  b_rangeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,RangeError,
642  "RangeError","RangeError"));
643  b_referenceErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,ReferenceError,
644  "ReferenceError","ReferenceError"));
645  b_syntaxErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,SyntaxError,
646  "SyntaxError","SyntaxError"));
647  b_typeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,TypeError,
648  "TypeError","TypeError"));
649  b_uriErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,URIError,
650  "URIError","URIError"));
651 
652  // Error objects
653  b_evalError = Object(new NativeErrorImp(globExec,funcProto,b_evalErrorPrototype));
654  b_rangeError = Object(new NativeErrorImp(globExec,funcProto,b_rangeErrorPrototype));
655  b_referenceError = Object(new NativeErrorImp(globExec,funcProto,b_referenceErrorPrototype));
656  b_syntaxError = Object(new NativeErrorImp(globExec,funcProto,b_syntaxErrorPrototype));
657  b_typeError = Object(new NativeErrorImp(globExec,funcProto,b_typeErrorPrototype));
658  b_uriError = Object(new NativeErrorImp(globExec,funcProto,b_uriErrorPrototype));
659 
660  // ECMA 15.3.4.1
661  funcProto->put(globExec,constructorPropertyName, b_Function, DontEnum);
662 
663  global.put(globExec,"Object", b_Object, DontEnum);
664  global.put(globExec,"Function", b_Function, DontEnum);
665  global.put(globExec,"Array", b_Array, DontEnum);
666  global.put(globExec,"Boolean", b_Boolean, DontEnum);
667  global.put(globExec,"String", b_String, DontEnum);
668  global.put(globExec,"Number", b_Number, DontEnum);
669  global.put(globExec,"Date", b_Date, DontEnum);
670  global.put(globExec,"RegExp", b_RegExp, DontEnum);
671  global.put(globExec,"Error", b_Error, DontEnum);
672  // Using Internal for those to have something != 0
673  // (see kjs_window). Maybe DontEnum would be ok too ?
674  global.put(globExec,"EvalError",b_evalError, Internal);
675  global.put(globExec,"RangeError",b_rangeError, Internal);
676  global.put(globExec,"ReferenceError",b_referenceError, Internal);
677  global.put(globExec,"SyntaxError",b_syntaxError, Internal);
678  global.put(globExec,"TypeError",b_typeError, Internal);
679  global.put(globExec,"URIError",b_uriError, Internal);
680 
681  // Set the "constructor" property of all builtin constructors
682  objProto->put(globExec, constructorPropertyName, b_Object, DontEnum | DontDelete | ReadOnly);
683  funcProto->put(globExec, constructorPropertyName, b_Function, DontEnum | DontDelete | ReadOnly);
684  arrayProto->put(globExec, constructorPropertyName, b_Array, DontEnum | DontDelete | ReadOnly);
685  booleanProto->put(globExec, constructorPropertyName, b_Boolean, DontEnum | DontDelete | ReadOnly);
686  stringProto->put(globExec, constructorPropertyName, b_String, DontEnum | DontDelete | ReadOnly);
687  numberProto->put(globExec, constructorPropertyName, b_Number, DontEnum | DontDelete | ReadOnly);
688  dateProto->put(globExec, constructorPropertyName, b_Date, DontEnum | DontDelete | ReadOnly);
689  regexpProto->put(globExec, constructorPropertyName, b_RegExp, DontEnum | DontDelete | ReadOnly);
690  errorProto->put(globExec, constructorPropertyName, b_Error, DontEnum | DontDelete | ReadOnly);
691  b_evalErrorPrototype.put(globExec, constructorPropertyName, b_evalError, DontEnum | DontDelete | ReadOnly);
692  b_rangeErrorPrototype.put(globExec, constructorPropertyName, b_rangeError, DontEnum | DontDelete | ReadOnly);
693  b_referenceErrorPrototype.put(globExec, constructorPropertyName, b_referenceError, DontEnum | DontDelete | ReadOnly);
694  b_syntaxErrorPrototype.put(globExec, constructorPropertyName, b_syntaxError, DontEnum | DontDelete | ReadOnly);
695  b_typeErrorPrototype.put(globExec, constructorPropertyName, b_typeError, DontEnum | DontDelete | ReadOnly);
696  b_uriErrorPrototype.put(globExec, constructorPropertyName, b_uriError, DontEnum | DontDelete | ReadOnly);
697 
698  // built-in values
699  global.put(globExec, "NaN", Number(NaN), DontEnum|DontDelete);
700  global.put(globExec, "Infinity", Number(Inf), DontEnum|DontDelete);
701  global.put(globExec, "undefined", Undefined(), DontEnum|DontDelete);
702 
703  // built-in functions
704 #ifdef KJS_PURE_ECMA // otherwise as deprecated Object.prototype property
705  global.put(globExec,"eval",
706  Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Eval,1,"eval")), DontEnum);
707 #endif
708  global.put(globExec,"parseInt",
709  Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseInt,2,"parseInt")), DontEnum);
710  global.put(globExec,"parseFloat",
711  Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseFloat,1,"parseFloat")), DontEnum);
712  global.put(globExec,"isNaN",
713  Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsNaN,1,"isNaN")), DontEnum);
714  global.put(globExec,"isFinite",
715  Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsFinite,1,"isFinite")), DontEnum);
716  global.put(globExec,"decodeURI",
717  Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::DecodeURI,1,"decodeURI")),
718  DontEnum);
719  global.put(globExec,"decodeURIComponent",
720  Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::DecodeURIComponent,1,"decodeURIComponent")),
721  DontEnum);
722  global.put(globExec,"encodeURI",
723  Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::EncodeURI,1,"encodeURI")),
724  DontEnum);
725  global.put(globExec,"encodeURIComponent",
726  Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::EncodeURIComponent,1,"encodeURIComponent")),
727  DontEnum);
728  global.put(globExec,"escape",
729  Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Escape,1,"escape")), DontEnum);
730  global.put(globExec,"unescape",
731  Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::UnEscape,1,"unescape")), DontEnum);
732 #ifndef NDEBUG
733  global.put(globExec,"kjsprint",
734  Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::KJSPrint,1,"kjsprint")), DontEnum);
735 #endif
736 
737  // built-in objects
738  global.put(globExec,"Math", Object(new MathObjectImp(globExec,objProto)), DontEnum);
739 }
740 
741 InterpreterImp::~InterpreterImp()
742 {
743  if (dbg)
744  dbg->detach(m_interpreter);
745  for (SourceCode *s = sources; s; s = s->next)
746  s->interpreter = 0;
747  delete globExec;
748  globExec = 0L;
749  clear();
750 }
751 
752 void InterpreterImp::clear()
753 {
754  //fprintf(stderr,"InterpreterImp::clear\n");
755  // remove from global chain (see init())
756  lockInterpreter();
757  next->prev = prev;
758  prev->next = next;
759  s_hook = next;
760  if (s_hook == this)
761  {
762  // This was the last interpreter
763  s_hook = 0L;
764  globalClear();
765  }
766  unlockInterpreter();
767 }
768 
769 void InterpreterImp::mark()
770 {
771  //if (exVal && !exVal->marked())
772  // exVal->mark();
773  //if (retVal && !retVal->marked())
774  // retVal->mark();
775  if (UndefinedImp::staticUndefined && !UndefinedImp::staticUndefined->marked())
776  UndefinedImp::staticUndefined->mark();
777  if (NullImp::staticNull && !NullImp::staticNull->marked())
778  NullImp::staticNull->mark();
779  if (NumberImp::staticNaN && !NumberImp::staticNaN->marked())
780  NumberImp::staticNaN->mark();
781  if (BooleanImp::staticTrue && !BooleanImp::staticTrue->marked())
782  BooleanImp::staticTrue->mark();
783  if (BooleanImp::staticFalse && !BooleanImp::staticFalse->marked())
784  BooleanImp::staticFalse->mark();
785  //fprintf( stderr, "[kjs-internal] InterpreterImp::mark this=%p global.imp()=%p\n", this, global.imp() );
786  if (global.imp())
787  global.imp()->mark();
788  if (m_interpreter)
789  m_interpreter->mark();
790  if (_context)
791  _context->mark();
792 }
793 
794 bool InterpreterImp::checkSyntax(const UString &code, int *errLine, UString *errMsg)
795 {
796  // Parser::parse() returns 0 in a syntax error occurs, so we just check for that
797  SourceCode *source;
798  FunctionBodyNode *progNode = Parser::parse(code.data(),code.size(),&source,errLine,errMsg);
799  source->deref();
800  bool ok = (progNode != 0);
801  delete progNode;
802  return ok;
803 }
804 
805 bool InterpreterImp::checkSyntax(const UString &code)
806 {
807  // Parser::parse() returns 0 in a syntax error occurs, so we just check for that
808  SourceCode *source;
809  FunctionBodyNode *progNode = Parser::parse(code.data(),code.size(),&source,0,0);
810  source->deref();
811  bool ok = (progNode != 0);
812  delete progNode;
813  return ok;
814 }
815 
816 Completion InterpreterImp::evaluate(const UString &code, const Value &thisV)
817 {
818  lockInterpreter();
819 
820  // prevent against infinite recursion
821  if (recursion >= 20) {
822  Completion result = Completion(Throw,Error::create(globExec,GeneralError,"Recursion too deep"));
823  unlockInterpreter();
824  return result;
825  }
826 
827  // parse the source code
828  int errLine;
829  UString errMsg;
830  SourceCode *source;
831  FunctionBodyNode *progNode = Parser::parse(code.data(),code.size(),&source,&errLine,&errMsg);
832 
833  // notify debugger that source has been parsed
834  if (dbg) {
835  bool cont = dbg->sourceParsed(globExec,source->sid,code,errLine);
836  if (!cont) {
837  source->deref();
838  if (progNode)
839  delete progNode;
840  unlockInterpreter();
841  return Completion(Break);
842  }
843  }
844 
845  addSourceCode(source);
846 
847  // no program node means a syntax error occurred
848  if (!progNode) {
849  Object err = Error::create(globExec,SyntaxError,errMsg.ascii(),errLine);
850  err.put(globExec,"sid",Number(source->sid));
851  globExec->setException(err); // required to notify the debugger
852  globExec->clearException();
853  source->deref();
854  unlockInterpreter();
855  return Completion(Throw,err);
856  }
857  source->deref();
858 
859  globExec->clearException();
860 
861  recursion++;
862  progNode->ref();
863 
864  Object &globalObj = globalObject();
865  Object thisObj = globalObject();
866 
867  if (thisV.isValid()) {
868  // "this" must be an object... use same rules as Function.prototype.apply()
869  if (thisV.isA(NullType) || thisV.isA(UndefinedType))
870  thisObj = globalObject();
871  else {
872  thisObj = thisV.toObject(globExec);
873  }
874  }
875 
876  Completion res;
877  if (globExec->hadException()) {
878  // the thisArg.toObject() conversion above might have thrown an exception - if so,
879  // propagate it back
880  res = Completion(Throw,globExec->exception());
881  }
882  else {
883  // execute the code
884  ContextImp ctx(globalObj, this, thisObj, source->sid);
885  ExecState newExec(m_interpreter,&ctx);
886 
887  // create variables (initialized to undefined until var statements
888  // with optional initializers are executed)
889  progNode->processVarDecls(&newExec);
890 
891  ctx.setLines(progNode->firstLine(),progNode->firstLine());
892  bool abort = false;
893  if (dbg) {
894  if (!dbg->enterContext(&newExec)) {
895  // debugger requested we stop execution
896  dbg->imp()->abort();
897  abort = true;
898  }
899  }
900 
901  if (!abort) {
902  ctx.setLines(progNode->lastLine(),progNode->lastLine());
903  res = progNode->execute(&newExec);
904  if (dbg && !dbg->exitContext(&newExec,res)) {
905  // debugger requested we stop execution
906  dbg->imp()->abort();
907  unlockInterpreter();
908  res = Completion(ReturnValue,Undefined());
909  }
910  }
911  }
912 
913  if (progNode->deref())
914  delete progNode;
915  recursion--;
916 
917  if (globExec->hadException()) {
918  res = Completion(Throw,globExec->exception());
919  globExec->clearException();
920  }
921 
922  unlockInterpreter();
923  return res;
924 }
925 
926 void InterpreterImp::setDebugger(Debugger *d)
927 {
928  if (d == dbg)
929  return;
930  // avoid recursion
931  Debugger *old = dbg;
932  dbg = d;
933  if ( old )
934  old->detach(m_interpreter);
935 }
936 
937 void InterpreterImp::addSourceCode(SourceCode *code)
938 {
939  assert(!code->next);
940  assert(!code->interpreter);
941  code->next = sources;
942  code->interpreter = this;
943  sources = code;
944 }
945 
946 void InterpreterImp::removeSourceCode(SourceCode *code)
947 {
948  assert(code);
949  assert(sources);
950 
951  if (code == sources) {
952  sources = sources->next;
953  return;
954  }
955 
956  SourceCode *prev = sources;
957  SourceCode *cur = sources->next;
958  while (cur != code) {
959  assert(cur);
960  prev = cur;
961  cur = cur->next;
962  }
963 
964  prev->next = cur->next;
965 }
966 
967 // ------------------------------ InternalFunctionImp --------------------------
968 
969 const ClassInfo InternalFunctionImp::info = {"Function", 0, 0, 0};
970 
971 InternalFunctionImp::InternalFunctionImp(FunctionPrototypeImp *funcProto)
972  : ObjectImp(funcProto)
973 {
974 }
975 
976 InternalFunctionImp::InternalFunctionImp(ExecState *exec)
977  : ObjectImp(static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp()))
978 {
979 }
980 
981 bool InternalFunctionImp::implementsHasInstance() const
982 {
983  return true;
984 }
985 
986 Boolean InternalFunctionImp::hasInstance(ExecState *exec, const Value &value)
987 {
988  if (value.type() != ObjectType)
989  return Boolean(false);
990 
991  Value prot = get(exec,prototypePropertyName);
992  if (prot.type() != ObjectType && prot.type() != NullType) {
993  Object err = Error::create(exec, TypeError, "Invalid prototype encountered "
994  "in instanceof operation.");
995  exec->setException(err);
996  return Boolean(false);
997  }
998 
999  Object v = Object(static_cast<ObjectImp*>(value.imp()));
1000  while ((v = Object::dynamicCast(v.prototype())).imp()) {
1001  if (v.imp() == prot.imp())
1002  return Boolean(true);
1003  }
1004  return Boolean(false);
1005 }
1006 
1007 // ------------------------------ global functions -----------------------------
1008 
1009 double KJS::roundValue(ExecState *exec, const Value &v)
1010 {
1011  double n = v.toNumber(exec);
1012  if (isNaN(n) || isInf(n))
1013  return n;
1014  double an = fabs(n);
1015  if (an == 0.0)
1016  return n;
1017  double d = floor(an);
1018  if (n < 0)
1019  d *= -1;
1020 
1021  return d;
1022 }
1023 
1024 #ifndef NDEBUG
1025 #include <stdio.h>
1026 void KJS::printInfo(ExecState *exec, const char *s, const Value &o, int lineno)
1027 {
1028  if (!o.isValid())
1029  fprintf(stderr, "KJS: %s: (null)", s);
1030  else {
1031  Value v = o;
1032  unsigned int arrayLength = 0;
1033  bool hadExcep = exec->hadException();
1034 
1035  UString name;
1036  switch ( v.type() ) {
1037  case UnspecifiedType:
1038  name = "Unspecified";
1039  break;
1040  case UndefinedType:
1041  name = "Undefined";
1042  break;
1043  case NullType:
1044  name = "Null";
1045  break;
1046  case BooleanType:
1047  name = "Boolean";
1048  break;
1049  case StringType:
1050  name = "String";
1051  break;
1052  case NumberType:
1053  name = "Number";
1054  break;
1055  case ObjectType: {
1056  Object obj = Object::dynamicCast(v);
1057  name = obj.className();
1058  if (name.isNull())
1059  name = "(unknown class)";
1060  if ( obj.inherits(&ArrayInstanceImp::info) )
1061  arrayLength = obj.get(exec,lengthPropertyName).toUInt32(exec);
1062  }
1063  break;
1064  }
1065  UString vString;
1066  // Avoid calling toString on a huge array (e.g. 4 billion elements, in mozilla/js/js1_5/Array/array-001.js)
1067  if ( arrayLength > 100 )
1068  vString = UString( "[ Array with " ) + UString::from( arrayLength ) + " elements ]";
1069  else
1070  vString = v.toString(exec);
1071  if ( !hadExcep )
1072  exec->clearException();
1073  if ( vString.size() > 50 )
1074  vString = vString.substr( 0, 50 ) + "...";
1075  // Can't use two UString::ascii() in the same fprintf call
1076  CString tempString( vString.cstring() );
1077 
1078  fprintf(stderr, "KJS: %s: %s : %s (%p)",
1079  s, tempString.c_str(), name.ascii(), (void*)v.imp());
1080 
1081  if (lineno >= 0)
1082  fprintf(stderr, ", line %d\n",lineno);
1083  else
1084  fprintf(stderr, "\n");
1085  }
1086 }
1087 #endif
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::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::InternalFunctionImp::InternalFunctionImp
InternalFunctionImp(FunctionPrototypeImp *funcProto)
Constructor.
Definition: internal.cpp:971
KJS::Interpreter
Interpreter objects can be used to evaluate ECMAScript code.
Definition: interpreter.h:172
KJS::Interpreter::builtinNumber
Object builtinNumber() const
Returns the builtin "Number" object.
Definition: interpreter.cpp:198
KJS::Interpreter::builtinString
Object builtinString() const
Returns the builtin "String" object.
Definition: interpreter.cpp:193
KJS::Interpreter::builtinBoolean
Object builtinBoolean() const
Returns the builtin "Boolean" object.
Definition: interpreter.cpp:188
KJS::LabelStack
The "label set" in Ecma-262 spec.
Definition: internal.h:161
KJS::LabelStack::pop
void pop()
Removes from the stack the last pushed id (what else?)
Definition: internal.cpp:344
KJS::LabelStack::contains
bool contains(const Identifier &id) const
Is the id in the stack?
Definition: internal.cpp:332
KJS::LabelStack::push
bool push(const Identifier &id)
If id is not empty and is not in the stack already, puts it on top of the stack and returns true,...
Definition: internal.cpp:320
KJS::List
Native list type.
Definition: list.h:48
KJS::List::append
void append(const Value &val)
Append an object to the end of the list.
Definition: list.h:66
KJS::Number
Represents an primitive Number value.
Definition: value.h:367
KJS::Object
Represents an Object.
Definition: object.h:81
KJS::Object::prototype
Value prototype() const
Returns the prototype of this object.
Definition: object.h:657
KJS::Object::construct
Object construct(ExecState *exec, const List &args)
Creates a new object based on this object.
Definition: object.h:696
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::Object::dynamicCast
static Object dynamicCast(const Value &v)
Converts a Value into an Object.
Definition: object.cpp:45
KJS::Object::get
Value get(ExecState *exec, const Identifier &propertyName) const
Retrieves the specified property from the object.
Definition: object.h:663
KJS::Object::className
UString className() const
Returns the class name of the object.
Definition: object.h:660
KJS::UString
Unicode string class.
Definition: ustring.h:189
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::UString::substr
UString substr(int pos=0, int len=-1) const
Definition: ustring.cpp:868
KJS::UString::cstring
CString cstring() const
Definition: ustring.cpp:480
KJS::UString::from
static UString from(int i)
Constructs a string from an int.
Definition: ustring.cpp:340
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::isA
bool isA(Type t) const
Checks whether or not the value is of a particular tpye.
Definition: value.h:203
KJS::Value::toObject
Object toObject(ExecState *exec) const
Performs the ToObject type conversion operation on this value (ECMA 9.9)
Definition: object.h:358
KJS::Value::toUInt32
unsigned int toUInt32(ExecState *exec) const
Performs the ToUInt32 type conversion operation on this value (ECMA 9.6)
Definition: value.h:236
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
KJS::Value::toNumber
double toNumber(ExecState *exec) const
Performs the ToNumber type conversion operation on this value (ECMA 9.3)
Definition: value.h:221
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.