• 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
49extern int kjsyyparse();
50
51using namespace KJS;
52
53namespace 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
74static pthread_once_t interpreterLockOnce = PTHREAD_ONCE_INIT;
75static pthread_mutex_t interpreterLock;
76static int interpreterLockCount = 0;
77
78static 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
89static inline void lockInterpreter()
90{
91#ifdef KJS_THREADSUPPORT
92 pthread_once(&interpreterLockOnce, initializeInterpreterLock);
93 pthread_mutex_lock(&interpreterLock);
94 interpreterLockCount++;
95#endif
96}
97
98static inline void unlockInterpreter()
99{
100#ifdef KJS_THREADSUPPORT
101 interpreterLockCount--;
102 pthread_mutex_unlock(&interpreterLock);
103#endif
104}
105
106
107
108// ------------------------------ UndefinedImp ---------------------------------
109
110UndefinedImp *UndefinedImp::staticUndefined = 0;
111
112Value UndefinedImp::toPrimitive(ExecState* /*exec*/, Type) const
113{
114 return Value((ValueImp*)this);
115}
116
117bool UndefinedImp::toBoolean(ExecState* /*exec*/) const
118{
119 return false;
120}
121
122double UndefinedImp::toNumber(ExecState* /*exec*/) const
123{
124 return NaN;
125}
126
127UString UndefinedImp::toString(ExecState* /*exec*/) const
128{
129 return "undefined";
130}
131
132Object 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
141NullImp *NullImp::staticNull = 0;
142
143Value NullImp::toPrimitive(ExecState* /*exec*/, Type) const
144{
145 return Value((ValueImp*)this);
146}
147
148bool NullImp::toBoolean(ExecState* /*exec*/) const
149{
150 return false;
151}
152
153double NullImp::toNumber(ExecState* /*exec*/) const
154{
155 return 0.0;
156}
157
158UString NullImp::toString(ExecState* /*exec*/) const
159{
160 return "null";
161}
162
163Object 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
172BooleanImp* BooleanImp::staticTrue = 0;
173BooleanImp* BooleanImp::staticFalse = 0;
174
175Value BooleanImp::toPrimitive(ExecState* /*exec*/, Type) const
176{
177 return Value((ValueImp*)this);
178}
179
180bool BooleanImp::toBoolean(ExecState* /*exec*/) const
181{
182 return val;
183}
184
185double BooleanImp::toNumber(ExecState* /*exec*/) const
186{
187 return val ? 1.0 : 0.0;
188}
189
190UString BooleanImp::toString(ExecState* /*exec*/) const
191{
192 return val ? "true" : "false";
193}
194
195Object 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
204Value StringImp::toPrimitive(ExecState* /*exec*/, Type) const
205{
206 return Value((ValueImp*)this);
207}
208
209bool StringImp::toBoolean(ExecState* /*exec*/) const
210{
211 return (val.size() > 0);
212}
213
214double StringImp::toNumber(ExecState* /*exec*/) const
215{
216 return val.toDouble();
217}
218
219UString StringImp::toString(ExecState* /*exec*/) const
220{
221 return val;
222}
223
224Object 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
233NumberImp *NumberImp::staticNaN;
234
235ValueImp *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
244ValueImp *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
255Value NumberImp::toPrimitive(ExecState *, Type) const
256{
257 return Number((NumberImp*)this);
258}
259
260bool NumberImp::toBoolean(ExecState *) const
261{
262 return !((val == 0) /* || (iVal() == N0) */ || isNaN(val));
263}
264
265double NumberImp::toNumber(ExecState *) const
266{
267 return val;
268}
269
270UString 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
277Object 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
284bool NumberImp::toUInt32(unsigned& uint32) const
285{
286 uint32 = (unsigned)val;
287 return (double)uint32 == val;
288}
289
290double SimpleNumber::negZero = -0.0;
291
292// ------------------------------ LabelStack -----------------------------------
293
294LabelStack::LabelStack(const LabelStack &other)
295{
296 tos = 0;
297 *this = other;
298}
299
300LabelStack &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
320bool 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
332bool 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
344void LabelStack::pop()
345{
346 if (tos) {
347 StackElem *prev = tos->prev;
348 delete tos;
349 tos = prev;
350 }
351}
352
353LabelStack::~LabelStack()
354{
355 clear();
356}
357
358void 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
373ContextImp::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
433ContextImp::~ContextImp()
434{
435 _interpreter->setContext(_callingContext);
436}
437
438void ContextImp::mark()
439{
440 for (ContextImp *context = this; context; context = context->_callingContext) {
441 context->scope.mark();
442 }
443}
444
445bool 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
455void 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
466FunctionBodyNode *Parser::progNode = 0;
467int Parser::sid = 0;
468SourceCode *Parser::source = 0;
469
470FunctionBodyNode *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
522InterpreterImp* InterpreterImp::s_hook = 0L;
523
524void 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
539void 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
559InterpreterImp::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
589void InterpreterImp::lock()
590{
591 lockInterpreter();
592}
593
594void InterpreterImp::unlock()
595{
596 unlockInterpreter();
597}
598
599void 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
741InterpreterImp::~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
752void 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
769void 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
794bool 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
805bool 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
816Completion 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
926void 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
937void 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
946void 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
969const ClassInfo InternalFunctionImp::info = {"Function", 0, 0, 0};
970
971InternalFunctionImp::InternalFunctionImp(FunctionPrototypeImp *funcProto)
972 : ObjectImp(funcProto)
973{
974}
975
976InternalFunctionImp::InternalFunctionImp(ExecState *exec)
977 : ObjectImp(static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp()))
978{
979}
980
981bool InternalFunctionImp::implementsHasInstance() const
982{
983 return true;
984}
985
986Boolean 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
1009double 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>
1026void 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::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::data
const UChar * data() const
Definition: ustring.h:339
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.4
This website is maintained by Timothy Pearson.