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

kjs

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

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
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kjs by doxygen 1.8.8
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |