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

kjs

  • kjs
nodes.cpp
1/*
2 * This file is part of the KDE libraries
3 * Copyright (C) 1999-2002, 2003 Harri Porten (porten@kde.org)
4 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
5 * Copyright (C) 2003 Apple Computer, Inc.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24#include "nodes.h"
25
26#include <math.h>
27#include <assert.h>
28#ifdef KJS_DEBUG_MEM
29#include <stdio.h>
30#include <typeinfo>
31#endif
32#ifdef KJS_VERBOSE
33#include <iostream>
34using namespace std;
35#endif
36
37#include "collector.h"
38#include "context.h"
39#include "debugger.h"
40#include "function_object.h"
41#include "internal.h"
42#include "value.h"
43#include "object.h"
44#include "types.h"
45#include "interpreter.h"
46#include "lexer.h"
47#include "operations.h"
48#include "ustring.h"
49
50using namespace KJS;
51
52#define KJS_BREAKPOINT \
53 if (!hitStatement(exec)) \
54 return Completion(Normal);
55
56#define KJS_ABORTPOINT \
57 if (exec->dynamicInterpreter()->imp()->debugger() && \
58 exec->dynamicInterpreter()->imp()->debugger()->imp()->aborted()) \
59 return Completion(Normal);
60
61#define KJS_CHECKEXCEPTION \
62 if (exec->hadException()) { \
63 setExceptionDetailsIfNeeded(exec); \
64 return Completion(Throw, exec->exception()); \
65 } \
66 if (Collector::outOfMemory()) \
67 return Completion(Throw, Error::create(exec,GeneralError,"Out of memory"));
68
69#define KJS_CHECKEXCEPTIONVALUE \
70 if (exec->hadException()) { \
71 setExceptionDetailsIfNeeded(exec); \
72 return exec->exception(); \
73 } \
74 if (Collector::outOfMemory()) \
75 return Undefined(); // will be picked up by KJS_CHECKEXCEPTION
76
77#define KJS_CHECKEXCEPTIONREFERENCE \
78 if (exec->hadException()) { \
79 setExceptionDetailsIfNeeded(exec); \
80 return Reference::makeValueReference(Undefined()); \
81 } \
82 if (Collector::outOfMemory()) \
83 return Reference::makeValueReference(Undefined()); // will be picked up by KJS_CHECKEXCEPTION
84
85#define KJS_CHECKEXCEPTIONLIST \
86 if (exec->hadException()) { \
87 setExceptionDetailsIfNeeded(exec); \
88 return List(); \
89 } \
90 if (Collector::outOfMemory()) \
91 return List(); // will be picked up by KJS_CHECKEXCEPTION
92
93#ifdef KJS_DEBUG_MEM
94std::list<Node *> * Node::s_nodes = 0L;
95#endif
96
97// ----------------------------- Node -----------------------------------------
98
99Node::Node()
100{
101 line = Lexer::curr()->lineNo();
102 refcount = 0;
103#ifdef KJS_DEBUG_MEM
104 if (!s_nodes)
105 s_nodes = new std::list<Node *>;
106 s_nodes->push_back(this);
107#endif
108}
109
110Node::~Node()
111{
112#ifdef KJS_DEBUG_MEM
113 s_nodes->remove( this );
114#endif
115}
116
117Reference Node::evaluateReference(ExecState *exec) const
118{
119 Value v = evaluate(exec);
120 KJS_CHECKEXCEPTIONREFERENCE
121 return Reference::makeValueReference(v);
122}
123
124// fallback for those nodes without a evaluate() reimplementation
125// TODO: reimplemint in each sub class, make Node::evaluate() pure virtual
126Value Node::evaluate(ExecState *exec) const
127{
128 // fprintf(stderr, "%s::evaluate()\n", typeid(*this).name());
129 return evaluateReference(exec).getValue(exec);
130}
131
132bool Node::toBoolean(ExecState *exec) const
133{
134// fprintf(stderr, "Node(%s)::toBoolean()\n", typeid(*this).name());
135 return evaluate(exec).toBoolean(exec);
136}
137
138double Node::toNumber(ExecState *exec) const
139{
140// fprintf(stderr, "Node(%s)::toNumber()\n", typeid(*this).name());
141 return evaluate(exec).toNumber(exec);
142}
143
144UString Node::toString(ExecState *exec) const
145{
146 return evaluate(exec).toString(exec);
147}
148
149#ifdef KJS_DEBUG_MEM
150void Node::finalCheck()
151{
152 if (!s_nodes) {
153 fprintf(stderr, "Node::finalCheck(): list 0\n");
154 return;
155 }
156 fprintf( stderr, "[nodes] Node::finalCheck(): list count : %d\n", (int)s_nodes->size() );
157 std::list<Node *>::iterator it = s_nodes->begin();
158 for ( uint i = 0; it != s_nodes->end() ; ++it, ++i )
159 fprintf( stderr, "[nodes] [%d] Still having node %p (%s) (refcount %d)\n", i, (void*)*it, typeid( **it ).name(), (*it)->refcount );
160 delete s_nodes;
161 s_nodes = 0L;
162}
163#endif
164
165Value Node::throwError(ExecState *exec, ErrorType e, const char *msg) const
166{
167 Object err = Error::create(exec, e, msg, lineNo(), sourceId());
168 exec->setException(err);
169 return err;
170}
171
172Value Node::throwError(ExecState *exec, ErrorType e, const char *msg,
173 const Value &v, const Node *expr) const
174{
175 char *vStr = strdup(v.toString(exec).ascii());
176 char *exprStr = strdup(expr->toCode().ascii());
177
178 int length = strlen(msg) - 4 /* two %s */ + strlen(vStr) + strlen(exprStr) + 1 /* null terminator */;
179 char *str = new char[length];
180 sprintf(str, msg, vStr, exprStr);
181 free(vStr);
182 free(exprStr);
183
184 Value result = throwError(exec, e, str);
185 delete [] str;
186
187 return result;
188}
189
190Value Node::throwError(ExecState *exec, ErrorType e, const char *msg, Identifier label) const
191{
192 const char *l = label.ascii();
193 int length = strlen(msg) - 2 /* %s */ + strlen(l) + 1 /* null terminator */;
194 char *message = new char[length];
195 sprintf(message, msg, l);
196
197 Value result = throwError(exec, e, message);
198 delete [] message;
199
200 return result;
201}
202
203
204void Node::setExceptionDetailsIfNeeded(ExecState *exec) const
205{
206 if (exec->hadException()) {
207 Object exception = exec->exception().toObject(exec);
208 if (!exception.hasProperty(exec, "line") /* &&
209 !exception.hasProperty(exec, "sourceURL")*/ ) {
210 exception.put(exec, "line", Number(line));
211// exception.put(exec, "sourceURL", String(sourceURL));
212 }
213 }
214}
215
216// ----------------------------- StatementNode --------------------------------
217StatementNode::StatementNode() : l0(-1), l1(-1), sourceCode(0), breakPoint(false)
218{
219}
220
221StatementNode::~StatementNode()
222{
223 if (sourceCode)
224 sourceCode->deref();
225}
226
227void StatementNode::setLoc(int line0, int line1, SourceCode *src)
228{
229 // ### require these to be passed to the constructor
230 l0 = line0;
231 l1 = line1;
232 if (sourceCode != src) {
233 if (sourceCode)
234 sourceCode->deref();
235 sourceCode = src;
236 sourceCode->ref();
237 }
238}
239
240// return true if the debugger wants us to stop at this point
241bool StatementNode::hitStatement(ExecState *exec)
242{
243 assert(sourceCode);
244 assert(exec->context().imp()->sourceId == sourceCode->sid);
245 exec->context().imp()->setLines(l0,l1);
246 Debugger *dbg = exec->dynamicInterpreter()->imp()->debugger();
247 if (dbg)
248 return dbg->atStatement(exec);
249 else
250 return true; // continue
251}
252
253// return true if the debugger wants us to stop at this point
254bool StatementNode::abortStatement(ExecState *exec)
255{
256 Debugger *dbg = exec->dynamicInterpreter()->imp()->debugger();
257 if (dbg)
258 return dbg->imp()->aborted();
259 else
260 return false;
261}
262
263void StatementNode::processFuncDecl(ExecState *)
264{
265}
266
267// ----------------------------- NullNode -------------------------------------
268
269Value NullNode::evaluate(ExecState *) const
270{
271 return Null();
272}
273
274bool NullNode::toBoolean(ExecState *) const
275{
276 return false;
277}
278
279double NullNode::toNumber(ExecState *) const
280{
281 return 0.0;
282}
283
284UString NullNode::toString(ExecState *) const
285{
286 return "null";
287}
288
289// ----------------------------- BooleanNode ----------------------------------
290
291Value BooleanNode::evaluate(ExecState *) const
292{
293 return Boolean(val);
294}
295
296bool BooleanNode::toBoolean(ExecState *) const
297{
298 return val;
299}
300
301double BooleanNode::toNumber(ExecState *) const
302{
303 return val ? 1.0 : 0.0;
304}
305
306UString BooleanNode::toString(ExecState *) const
307{
308 return val ? "true" : "false";
309}
310
311// ----------------------------- NumberNode -----------------------------------
312
313Value NumberNode::evaluate(ExecState *) const
314{
315 return Number(val);
316}
317
318bool NumberNode::toBoolean(ExecState *) const
319{
320 return !((val == 0) /* || (iVal() == N0) */ || isNaN(val));
321}
322
323double NumberNode::toNumber(ExecState *) const
324{
325 return val;
326}
327
328UString NumberNode::toString(ExecState *) const
329{
330 return UString::from(val);
331}
332
333// ----------------------------- StringNode -----------------------------------
334
335Value StringNode::evaluate(ExecState *) const
336{
337 return String(val);
338}
339
340bool StringNode::toBoolean(ExecState *) const
341{
342 return !val.isEmpty();
343}
344
345double StringNode::toNumber(ExecState *) const
346{
347 return val.toDouble();
348}
349
350UString StringNode::toString(ExecState *) const
351{
352 return val;
353}
354
355// ----------------------------- RegExpNode -----------------------------------
356
357Value RegExpNode::evaluate(ExecState *exec) const
358{
359 List list;
360 String p(pattern);
361 String f(flags);
362 list.append(p);
363 list.append(f);
364
365 Object reg = exec->lexicalInterpreter()->imp()->builtinRegExp();
366 return reg.construct(exec,list);
367}
368
369bool RegExpNode::toBoolean(ExecState *) const
370{
371 return true;
372}
373
374// ----------------------------- ThisNode -------------------------------------
375
376// ECMA 11.1.1
377Value ThisNode::evaluate(ExecState *exec) const
378{
379 return exec->context().imp()->thisValue();
380}
381
382// ----------------------------- ResolveNode ----------------------------------
383
384// ECMA 11.1.2 & 10.1.4
385Value ResolveNode::evaluate(ExecState *exec) const
386{
387 return evaluateReference(exec).getValue(exec);
388}
389
390Reference ResolveNode::evaluateReference(ExecState *exec) const
391{
392 ScopeChain chain = exec->context().imp()->scopeChain();
393
394 while (!chain.isEmpty()) {
395 ObjectImp *o = chain.top();
396
397 //cerr << "Resolve: looking at '" << ident.ascii() << "'"
398 // << " in " << (void*)o << " " << o->classInfo()->className << endl;
399 if (o->hasProperty(exec,ident)) {
400 //cerr << "Resolve: FOUND '" << ident.ascii() << "'"
401 // << " in " << (void*)o << " " << o->classInfo()->className << endl;
402 return Reference(o, ident);
403 }
404
405 chain.pop();
406 }
407
408 // identifier not found
409#ifdef KJS_VERBOSE
410 cerr << "Resolve::evaluateReference: didn't find '" << ident.ustring().ascii() << "'" << endl;
411#endif
412 return Reference(Null(), ident);
413}
414
415// ----------------------------- GroupNode ------------------------------------
416
417void GroupNode::ref()
418{
419 Node::ref();
420 if ( group )
421 group->ref();
422}
423
424bool GroupNode::deref()
425{
426 if ( group && group->deref() )
427 delete group;
428 return Node::deref();
429}
430
431// ECMA 11.1.6
432Value GroupNode::evaluate(ExecState *exec) const
433{
434 return group->evaluate(exec);
435}
436
437Reference GroupNode::evaluateReference(ExecState *exec) const
438{
439 return group->evaluateReference(exec);
440}
441
442// ----------------------------- ElementNode ----------------------------------
443
444void ElementNode::ref()
445{
446 for (ElementNode *n = this; n; n = n->list) {
447 n->Node::ref();
448 if (n->node)
449 n->node->ref();
450 }
451}
452
453bool ElementNode::deref()
454{
455 ElementNode *next;
456 for (ElementNode *n = this; n; n = next) {
457 next = n->list;
458 if (n->node && n->node->deref())
459 delete n->node;
460 if (n != this && n->Node::deref())
461 delete n;
462 }
463 return Node::deref();
464}
465
466// ECMA 11.1.4
467Value ElementNode::evaluate(ExecState *exec) const
468{
469 Object array = exec->lexicalInterpreter()->builtinArray().construct(exec, List::empty());
470 int length = 0;
471 for (const ElementNode *n = this; n; n = n->list) {
472 Value val = n->node->evaluate(exec);
473 KJS_CHECKEXCEPTIONVALUE
474 length += n->elision;
475 array.put(exec, length++, val);
476 }
477 return array;
478}
479
480// ----------------------------- ArrayNode ------------------------------------
481
482void ArrayNode::ref()
483{
484 Node::ref();
485 if ( element )
486 element->ref();
487}
488
489bool ArrayNode::deref()
490{
491 if ( element && element->deref() )
492 delete element;
493 return Node::deref();
494}
495
496// ECMA 11.1.4
497Value ArrayNode::evaluate(ExecState *exec) const
498{
499 Object array;
500 int length;
501
502 if (element) {
503 array = Object(static_cast<ObjectImp*>(element->evaluate(exec).imp()));
504 KJS_CHECKEXCEPTIONVALUE
505 length = opt ? array.get(exec,lengthPropertyName).toInt32(exec) : 0;
506 } else {
507 Value newArr = exec->lexicalInterpreter()->builtinArray().construct(exec,List::empty());
508 array = Object(static_cast<ObjectImp*>(newArr.imp()));
509 length = 0;
510 }
511
512 if (opt)
513 array.put(exec,lengthPropertyName, Number(elision + length), DontEnum | DontDelete);
514
515 return array;
516}
517
518// ----------------------------- ObjectLiteralNode ----------------------------
519
520void ObjectLiteralNode::ref()
521{
522 Node::ref();
523 if ( list )
524 list->ref();
525}
526
527bool ObjectLiteralNode::deref()
528{
529 if ( list && list->deref() )
530 delete list;
531 return Node::deref();
532}
533
534// ECMA 11.1.5
535Value ObjectLiteralNode::evaluate(ExecState *exec) const
536{
537 if (list)
538 return list->evaluate(exec);
539
540 return exec->lexicalInterpreter()->builtinObject().construct(exec,List::empty());
541}
542
543// ----------------------------- PropertyValueNode ----------------------------
544
545void PropertyValueNode::ref()
546{
547 for (PropertyValueNode *n = this; n; n = n->list) {
548 n->Node::ref();
549 if (n->name)
550 n->name->ref();
551 if (n->assign)
552 n->assign->ref();
553 }
554}
555
556bool PropertyValueNode::deref()
557{
558 PropertyValueNode *next;
559 for (PropertyValueNode *n = this; n; n = next) {
560 next = n->list;
561 if ( n->name && n->name->deref() )
562 delete n->name;
563 if ( n->assign && n->assign->deref() )
564 delete n->assign;
565 if (n != this && n->Node::deref() )
566 delete n;
567 }
568 return Node::deref();
569}
570
571// ECMA 11.1.5
572Value PropertyValueNode::evaluate(ExecState *exec) const
573{
574 Object obj = exec->lexicalInterpreter()->builtinObject().construct(exec, List::empty());
575
576 for (const PropertyValueNode *p = this; p; p = p->list) {
577 Value n = p->name->evaluate(exec);
578 KJS_CHECKEXCEPTIONVALUE
579 Value v = p->assign->evaluate(exec);
580 KJS_CHECKEXCEPTIONVALUE
581
582 obj.put(exec, Identifier(n.toString(exec)), v);
583 }
584
585 return obj;
586}
587
588// ----------------------------- PropertyNode ---------------------------------
589
590// ECMA 11.1.5
591Value PropertyNode::evaluate(ExecState * /*exec*/) const
592{
593 Value s;
594
595 if (str.isNull()) {
596 s = String(UString::from(numeric));
597 } else {
598 s = String(str.ustring());
599 }
600
601 return s;
602}
603
604// ----------------------------- AccessorNode1 --------------------------------
605
606void AccessorNode1::ref()
607{
608 Node::ref();
609 if ( expr1 )
610 expr1->ref();
611 if ( expr2 )
612 expr2->ref();
613}
614
615bool AccessorNode1::deref()
616{
617 if ( expr1 && expr1->deref() )
618 delete expr1;
619 if ( expr2 && expr2->deref() )
620 delete expr2;
621 return Node::deref();
622}
623
624// ECMA 11.2.1a
625Reference AccessorNode1::evaluateReference(ExecState *exec) const
626{
627 Value v1 = expr1->evaluate(exec);
628 KJS_CHECKEXCEPTIONREFERENCE
629 Value v2 = expr2->evaluate(exec);
630 KJS_CHECKEXCEPTIONREFERENCE
631#ifndef NDEBUG
632 // catch errors before being caught in toObject(). better error message.
633 if (v1.isA(UndefinedType) || v1.isA(NullType)) {
634 UString s = "Attempted to access property on %s object "
635 "(result of expression %s)";
636 (void)throwError(exec, TypeError, s.cstring().c_str(), v1, this);
637 return Reference::makeValueReference(Undefined());
638 }
639#endif
640 Object o = v1.toObject(exec);
641 unsigned i;
642 if (v2.toUInt32(i))
643 return Reference(o, i);
644 UString s = v2.toString(exec);
645 return Reference(o, Identifier(s));
646}
647
648// ----------------------------- AccessorNode2 --------------------------------
649
650void AccessorNode2::ref()
651{
652 Node::ref();
653 if ( expr )
654 expr->ref();
655}
656
657bool AccessorNode2::deref()
658{
659 if ( expr && expr->deref() )
660 delete expr;
661 return Node::deref();
662}
663
664// ECMA 11.2.1b
665Reference AccessorNode2::evaluateReference(ExecState *exec) const
666{
667 Value v = expr->evaluate(exec);
668 KJS_CHECKEXCEPTIONREFERENCE
669 assert(v.isValid());
670#ifndef NDEBUG
671 // catch errors before being caught in toObject(). better error message.
672 if (v.isA(UndefinedType) || v.isA(NullType)) {
673 UString s = "Attempted to access '" + ident.ustring() +
674 "' property on %s object (result of expression %s)";
675 (void)throwError(exec, TypeError, s.cstring().c_str(), v, this);
676 return Reference::makeValueReference(Undefined());
677 }
678#endif
679 Object o = v.toObject(exec);
680 return Reference(o, ident);
681}
682
683// ----------------------------- ArgumentListNode -----------------------------
684
685void ArgumentListNode::ref()
686{
687 for (ArgumentListNode *n = this; n; n = n->list) {
688 n->Node::ref();
689 if (n->expr)
690 n->expr->ref();
691 }
692}
693
694bool ArgumentListNode::deref()
695{
696 ArgumentListNode *next;
697 for (ArgumentListNode *n = this; n; n = next) {
698 next = n->list;
699 if (n->expr && n->expr->deref())
700 delete n->expr;
701 if (n != this && n->Node::deref())
702 delete n;
703 }
704 return Node::deref();
705}
706
707Value ArgumentListNode::evaluate(ExecState * /*exec*/) const
708{
709 assert(0);
710 return Value(); // dummy, see evaluateList()
711}
712
713// ECMA 11.2.4
714List ArgumentListNode::evaluateList(ExecState *exec) const
715{
716 List l;
717
718 for (const ArgumentListNode *n = this; n; n = n->list) {
719 Value v = n->expr->evaluate(exec);
720 KJS_CHECKEXCEPTIONLIST
721 l.append(v);
722 }
723
724 return l;
725}
726
727// ----------------------------- ArgumentsNode --------------------------------
728
729void ArgumentsNode::ref()
730{
731 Node::ref();
732 if ( list )
733 list->ref();
734}
735
736bool ArgumentsNode::deref()
737{
738 if ( list && list->deref() )
739 delete list;
740 return Node::deref();
741}
742
743Value ArgumentsNode::evaluate(ExecState * /*exec*/) const
744{
745 assert(0);
746 return Value(); // dummy, see evaluateList()
747}
748
749// ECMA 11.2.4
750List ArgumentsNode::evaluateList(ExecState *exec) const
751{
752 if (!list)
753 return List();
754
755 return list->evaluateList(exec);
756}
757
758// ----------------------------- NewExprNode ----------------------------------
759
760// ECMA 11.2.2
761
762void NewExprNode::ref()
763{
764 Node::ref();
765 if ( expr )
766 expr->ref();
767 if ( args )
768 args->ref();
769}
770
771bool NewExprNode::deref()
772{
773 if ( expr && expr->deref() )
774 delete expr;
775 if ( args && args->deref() )
776 delete args;
777 return Node::deref();
778}
779
780Value NewExprNode::evaluate(ExecState *exec) const
781{
782 Value v = expr->evaluate(exec);
783 KJS_CHECKEXCEPTIONVALUE
784
785 List argList;
786 if (args) {
787 argList = args->evaluateList(exec);
788 KJS_CHECKEXCEPTIONVALUE
789 }
790
791 if (v.type() != ObjectType) {
792 return throwError(exec, TypeError, "Value %s (result of expression %s) is not an object. Cannot be used with new.", v, expr);
793 }
794
795 Object constr = Object(static_cast<ObjectImp*>(v.imp()));
796 if (!constr.implementsConstruct()) {
797 return throwError(exec, TypeError, "Value %s (result of expression %s) is not a constructor. Cannot be used with new.", v, expr);
798 }
799
800 Value res = constr.construct(exec,argList);
801
802 return res;
803}
804
805// ----------------------------- FunctionCallNode -----------------------------
806
807void FunctionCallNode::ref()
808{
809 Node::ref();
810 if ( expr )
811 expr->ref();
812 if ( args )
813 args->ref();
814}
815
816bool FunctionCallNode::deref()
817{
818 if ( expr && expr->deref() )
819 delete expr;
820 if ( args && args->deref() )
821 delete args;
822 return Node::deref();
823}
824
825// ECMA 11.2.3
826Value FunctionCallNode::evaluate(ExecState *exec) const
827{
828 Reference ref = expr->evaluateReference(exec);
829 KJS_CHECKEXCEPTIONVALUE
830
831 List argList = args->evaluateList(exec);
832 KJS_CHECKEXCEPTIONVALUE
833
834 Value v = ref.getValue(exec);
835 KJS_CHECKEXCEPTIONVALUE
836
837 if (v.type() != ObjectType) {
838 return throwError(exec, TypeError, "Value %s (result of expression %s) is not an object. Cannot be called.", v, expr);
839 }
840
841 Object func = Object(static_cast<ObjectImp*>(v.imp()));
842
843 if (!func.implementsCall()) {
844 return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, expr);
845 }
846
847 Value thisVal;
848 if (ref.isMutable())
849 thisVal = ref.getBase(exec);
850 else
851 thisVal = Null();
852
853 if (thisVal.type() == ObjectType &&
854 Object::dynamicCast(thisVal).inherits(&ActivationImp::info))
855 thisVal = Null();
856
857 if (thisVal.type() != ObjectType) {
858 // ECMA 11.2.3 says that in this situation the this value should be null.
859 // However, section 10.2.3 says that in the case where the value provided
860 // by the caller is null, the global object should be used. It also says
861 // that the section does not apply to interal functions, but for simplicity
862 // of implementation we use the global object anyway here. This guarantees
863 // that in host objects you always get a valid object for this.
864 // thisVal = Null();
865 thisVal = exec->dynamicInterpreter()->globalObject();
866 }
867
868 Object thisObj = Object::dynamicCast(thisVal);
869 Value result = func.call(exec,thisObj, argList);
870
871 return result;
872}
873
874// ----------------------------- PostfixNode ----------------------------------
875
876void PostfixNode::ref()
877{
878 Node::ref();
879 if ( expr )
880 expr->ref();
881}
882
883bool PostfixNode::deref()
884{
885 if ( expr && expr->deref() )
886 delete expr;
887 return Node::deref();
888}
889
890// ECMA 11.3
891Value PostfixNode::evaluate(ExecState *exec) const
892{
893 Reference ref = expr->evaluateReference(exec);
894 KJS_CHECKEXCEPTIONVALUE
895 Value v = ref.getValue(exec);
896 double n = v.toNumber(exec);
897
898 double newValue = (oper == OpPlusPlus) ? n + 1 : n - 1;
899
900 ref.putValue(exec, Number(newValue));
901
902 return Number(n);
903}
904
905// ----------------------------- DeleteNode -----------------------------------
906
907void DeleteNode::ref()
908{
909 Node::ref();
910 if ( expr )
911 expr->ref();
912}
913
914bool DeleteNode::deref()
915{
916 if ( expr && expr->deref() )
917 delete expr;
918 return Node::deref();
919}
920
921// ECMA 11.4.1
922Value DeleteNode::evaluate(ExecState *exec) const
923{
924 Reference ref = expr->evaluateReference(exec);
925 KJS_CHECKEXCEPTIONVALUE
926 return Boolean(ref.deleteValue(exec));
927}
928
929// ----------------------------- VoidNode -------------------------------------
930
931void VoidNode::ref()
932{
933 Node::ref();
934 if ( expr )
935 expr->ref();
936}
937
938bool VoidNode::deref()
939{
940 if ( expr && expr->deref() )
941 delete expr;
942 return Node::deref();
943}
944
945// ECMA 11.4.2
946Value VoidNode::evaluate(ExecState *exec) const
947{
948 Value dummy1 = expr->evaluate(exec);
949 KJS_CHECKEXCEPTIONVALUE
950
951 return Undefined();
952}
953
954// ----------------------------- TypeOfNode -----------------------------------
955
956void TypeOfNode::ref()
957{
958 Node::ref();
959 if ( expr )
960 expr->ref();
961}
962
963bool TypeOfNode::deref()
964{
965 if ( expr && expr->deref() )
966 delete expr;
967 return Node::deref();
968}
969
970// ECMA 11.4.3
971Value TypeOfNode::evaluate(ExecState *exec) const
972{
973 const char *s = 0L;
974 Reference ref = expr->evaluateReference(exec);
975 KJS_CHECKEXCEPTIONVALUE
976 if (ref.isMutable()) {
977 Value b = ref.getBase(exec);
978 if (b.type() == NullType)
979 return String("undefined");
980 }
981 Value v = ref.getValue(exec);
982 switch (v.type())
983 {
984 case UndefinedType:
985 s = "undefined";
986 break;
987 case NullType:
988 s = "object";
989 break;
990 case BooleanType:
991 s = "boolean";
992 break;
993 case NumberType:
994 s = "number";
995 break;
996 case StringType:
997 s = "string";
998 break;
999 default:
1000 if (v.type() == ObjectType && static_cast<ObjectImp*>(v.imp())->implementsCall())
1001 s = "function";
1002 else
1003 s = "object";
1004 break;
1005 }
1006
1007 return String(s);
1008}
1009
1010// ----------------------------- PrefixNode -----------------------------------
1011
1012void PrefixNode::ref()
1013{
1014 Node::ref();
1015 if ( expr )
1016 expr->ref();
1017}
1018
1019bool PrefixNode::deref()
1020{
1021 if ( expr && expr->deref() )
1022 delete expr;
1023 return Node::deref();
1024}
1025
1026// ECMA 11.4.4 and 11.4.5
1027Value PrefixNode::evaluate(ExecState *exec) const
1028{
1029 Reference ref = expr->evaluateReference(exec);
1030 KJS_CHECKEXCEPTIONVALUE
1031 Value v = ref.getValue(exec);
1032 double n = v.toNumber(exec);
1033
1034 double newValue = (oper == OpPlusPlus) ? n + 1 : n - 1;
1035 Value n2 = Number(newValue);
1036
1037 ref.putValue(exec,n2);
1038
1039 return n2;
1040}
1041
1042// ----------------------------- UnaryPlusNode --------------------------------
1043
1044void UnaryPlusNode::ref()
1045{
1046 Node::ref();
1047 if ( expr )
1048 expr->ref();
1049}
1050
1051bool UnaryPlusNode::deref()
1052{
1053 if ( expr && expr->deref() )
1054 delete expr;
1055 return Node::deref();
1056}
1057
1058// ECMA 11.4.6
1059double UnaryPlusNode::toNumber(ExecState *exec) const
1060{
1061 return expr->toNumber(exec);
1062}
1063
1064// could go
1065Value UnaryPlusNode::evaluate(ExecState *exec) const
1066{
1067 Value v = expr->evaluate(exec);
1068 KJS_CHECKEXCEPTIONVALUE
1069
1070 return Number(v.toNumber(exec)); /* TODO: optimize */
1071}
1072
1073// ----------------------------- NegateNode -----------------------------------
1074
1075void NegateNode::ref()
1076{
1077 Node::ref();
1078 if ( expr )
1079 expr->ref();
1080}
1081
1082bool NegateNode::deref()
1083{
1084 if ( expr && expr->deref() )
1085 delete expr;
1086 return Node::deref();
1087}
1088
1089// ECMA 11.4.7
1090double NegateNode::toNumber(ExecState *exec) const
1091{
1092 return -expr->toNumber(exec);
1093}
1094
1095Value NegateNode::evaluate(ExecState *exec) const
1096{
1097 Value v = expr->evaluate(exec);
1098 KJS_CHECKEXCEPTIONVALUE
1099 double d = -v.toNumber(exec);
1100
1101 return Number(d);
1102}
1103
1104// ----------------------------- BitwiseNotNode -------------------------------
1105
1106void BitwiseNotNode::ref()
1107{
1108 Node::ref();
1109 if ( expr )
1110 expr->ref();
1111}
1112
1113bool BitwiseNotNode::deref()
1114{
1115 if ( expr && expr->deref() )
1116 delete expr;
1117 return Node::deref();
1118}
1119
1120// ECMA 11.4.8
1121Value BitwiseNotNode::evaluate(ExecState *exec) const
1122{
1123 Value v = expr->evaluate(exec);
1124 KJS_CHECKEXCEPTIONVALUE
1125 int i32 = v.toInt32(exec);
1126
1127 return Number(~i32);
1128}
1129
1130// ----------------------------- LogicalNotNode -------------------------------
1131
1132void LogicalNotNode::ref()
1133{
1134 Node::ref();
1135 if ( expr )
1136 expr->ref();
1137}
1138
1139bool LogicalNotNode::deref()
1140{
1141 if ( expr && expr->deref() )
1142 delete expr;
1143 return Node::deref();
1144}
1145
1146// ECMA 11.4.9
1147bool LogicalNotNode::toBoolean(ExecState *exec) const
1148{
1149 return !expr->toBoolean(exec);
1150}
1151
1152// could remove this
1153Value LogicalNotNode::evaluate(ExecState *exec) const
1154{
1155 bool b = expr->toBoolean(exec);
1156 KJS_CHECKEXCEPTIONVALUE
1157
1158 return Boolean(!b);
1159}
1160
1161// ----------------------------- MultNode -------------------------------------
1162
1163void MultNode::ref()
1164{
1165 Node::ref();
1166 if ( term1 )
1167 term1->ref();
1168 if ( term2 )
1169 term2->ref();
1170}
1171
1172bool MultNode::deref()
1173{
1174 if ( term1 && term1->deref() )
1175 delete term1;
1176 if ( term2 && term2->deref() )
1177 delete term2;
1178 return Node::deref();
1179}
1180
1181// ECMA 11.5
1182Value MultNode::evaluate(ExecState *exec) const
1183{
1184 Value v1 = term1->evaluate(exec);
1185 KJS_CHECKEXCEPTIONVALUE
1186
1187 Value v2 = term2->evaluate(exec);
1188 KJS_CHECKEXCEPTIONVALUE
1189
1190 return mult(exec,v1, v2, oper);
1191}
1192
1193// ----------------------------- AddNode --------------------------------------
1194
1195// factory for an appropriate addition or substraction node
1196Node* AddNode::create(Node *t1, Node *t2, char op)
1197{
1198 // ### many more combinations to check for
1199 // fold constants
1200 if ((t1->type() == NumberType || t1->type() == BooleanType) &&
1201 (t2->type() == NumberType || t2->type() == BooleanType)) {
1202 double d = t2->toNumber(0);
1203 Node* n = new NumberNode(t1->toNumber(0) + (op == '+' ? d : -d));
1204 delete t1;
1205 delete t2;
1206 return n;
1207 }
1208
1209 if (op == '+' && t2->type() == StringType)
1210 return new AppendStringNode(t1, t2->toString(0));
1211
1212 // fall back to generic node
1213 return new AddNode(t1, t2, op);
1214}
1215
1216void AddNode::ref()
1217{
1218 Node::ref();
1219 if ( term1 )
1220 term1->ref();
1221 if ( term2 )
1222 term2->ref();
1223}
1224
1225bool AddNode::deref()
1226{
1227 if ( term1 && term1->deref() )
1228 delete term1;
1229 if ( term2 && term2->deref() )
1230 delete term2;
1231 return Node::deref();
1232}
1233
1234// ECMA 11.6
1235Value AddNode::evaluate(ExecState *exec) const
1236{
1237 Value v1 = term1->evaluate(exec);
1238 KJS_CHECKEXCEPTIONVALUE
1239
1240 Value v2 = term2->evaluate(exec);
1241 KJS_CHECKEXCEPTIONVALUE
1242
1243 return add(exec,v1, v2, oper);
1244}
1245
1246// ------------------------ AddNumberNode ------------------------------------
1247
1248void AppendStringNode::ref()
1249{
1250 Node::ref();
1251 term->ref();
1252}
1253
1254bool AppendStringNode::deref()
1255{
1256 if (term->deref())
1257 delete term;
1258 return Node::deref();
1259}
1260
1261// ECMA 11.6 (special case of string appending)
1262Value AppendStringNode::evaluate(ExecState *exec) const
1263{
1264 UString s = term->toString(exec);
1265 KJS_CHECKEXCEPTIONVALUE
1266
1267 return String(s + str);
1268}
1269
1270// ----------------------------- ShiftNode ------------------------------------
1271
1272void ShiftNode::ref()
1273{
1274 Node::ref();
1275 if ( term1 )
1276 term1->ref();
1277 if ( term2 )
1278 term2->ref();
1279}
1280
1281bool ShiftNode::deref()
1282{
1283 if ( term1 && term1->deref() )
1284 delete term1;
1285 if ( term2 && term2->deref() )
1286 delete term2;
1287 return Node::deref();
1288}
1289
1290// ECMA 11.7
1291Value ShiftNode::evaluate(ExecState *exec) const
1292{
1293 Value v1 = term1->evaluate(exec);
1294 KJS_CHECKEXCEPTIONVALUE
1295 Value v2 = term2->evaluate(exec);
1296 KJS_CHECKEXCEPTIONVALUE
1297 unsigned int i2 = v2.toUInt32(exec);
1298 i2 &= 0x1f;
1299
1300 switch (oper) {
1301 case OpLShift:
1302 return Number(v1.toInt32(exec) << i2);
1303 case OpRShift:
1304 return Number(v1.toInt32(exec) >> i2);
1305 case OpURShift:
1306 return Number(v1.toUInt32(exec) >> i2);
1307 default:
1308 assert(!"ShiftNode: unhandled switch case");
1309 return Undefined();
1310 }
1311}
1312
1313// ----------------------------- RelationalNode -------------------------------
1314
1315void RelationalNode::ref()
1316{
1317 Node::ref();
1318 if ( expr1 )
1319 expr1->ref();
1320 if ( expr2 )
1321 expr2->ref();
1322}
1323
1324bool RelationalNode::deref()
1325{
1326 if ( expr1 && expr1->deref() )
1327 delete expr1;
1328 if ( expr2 && expr2->deref() )
1329 delete expr2;
1330 return Node::deref();
1331}
1332
1333// ECMA 11.8
1334Value RelationalNode::evaluate(ExecState *exec) const
1335{
1336 Value v1 = expr1->evaluate(exec);
1337 KJS_CHECKEXCEPTIONVALUE
1338 Value v2 = expr2->evaluate(exec);
1339 KJS_CHECKEXCEPTIONVALUE
1340
1341 bool b;
1342 if (oper == OpLess || oper == OpGreaterEq) {
1343 int r = relation(exec, v1, v2);
1344 if (r < 0)
1345 b = false;
1346 else
1347 b = (oper == OpLess) ? (r == 1) : (r == 0);
1348 } else if (oper == OpGreater || oper == OpLessEq) {
1349 int r = relation(exec, v2, v1);
1350 if (r < 0)
1351 b = false;
1352 else
1353 b = (oper == OpGreater) ? (r == 1) : (r == 0);
1354 } else if (oper == OpIn) {
1355 // Is all of this OK for host objects?
1356 if (v2.type() != ObjectType)
1357 return throwError(exec, TypeError,
1358 "Value %s (result of expression %s) is not an object. Cannot be used with IN expression.", v2, expr2);
1359 Object o2(static_cast<ObjectImp*>(v2.imp()));
1360 b = o2.hasProperty(exec,Identifier(v1.toString(exec)));
1361 } else {
1362 if (v2.type() != ObjectType)
1363 return throwError(exec, TypeError,
1364 "Value %s (result of expression %s) is not an object. Cannot be used with instanceof operator.", v2, expr2);
1365
1366 Object o2(static_cast<ObjectImp*>(v2.imp()));
1367 if (!o2.implementsHasInstance()) {
1368 // According to the spec, only some types of objects "imlement" the [[HasInstance]] property.
1369 // But we are supposed to throw an exception where the object does not "have" the [[HasInstance]]
1370 // property. It seems that all object have the property, but not all implement it, so in this
1371 // case we return false (consistent with mozilla)
1372 return Boolean(false);
1373 // return throwError(exec, TypeError,
1374 // "Object does not implement the [[HasInstance]] method." );
1375 }
1376 return o2.hasInstance(exec, v1);
1377 }
1378
1379 return Boolean(b);
1380}
1381
1382// ----------------------------- EqualNode ------------------------------------
1383
1384void EqualNode::ref()
1385{
1386 Node::ref();
1387 if ( expr1 )
1388 expr1->ref();
1389 if ( expr2 )
1390 expr2->ref();
1391}
1392
1393bool EqualNode::deref()
1394{
1395 if ( expr1 && expr1->deref() )
1396 delete expr1;
1397 if ( expr2 && expr2->deref() )
1398 delete expr2;
1399 return Node::deref();
1400}
1401
1402// ECMA 11.9
1403Value EqualNode::evaluate(ExecState *exec) const
1404{
1405 Value v1 = expr1->evaluate(exec);
1406 KJS_CHECKEXCEPTIONVALUE
1407 Value v2 = expr2->evaluate(exec);
1408 KJS_CHECKEXCEPTIONVALUE
1409
1410 bool result;
1411 if (oper == OpEqEq || oper == OpNotEq) {
1412 // == and !=
1413 bool eq = equal(exec,v1, v2);
1414 result = oper == OpEqEq ? eq : !eq;
1415 } else {
1416 // === and !==
1417 bool eq = strictEqual(exec,v1, v2);
1418 result = oper == OpStrEq ? eq : !eq;
1419 }
1420 return Boolean(result);
1421}
1422
1423// ----------------------------- BitOperNode ----------------------------------
1424
1425void BitOperNode::ref()
1426{
1427 Node::ref();
1428 if ( expr1 )
1429 expr1->ref();
1430 if ( expr2 )
1431 expr2->ref();
1432}
1433
1434bool BitOperNode::deref()
1435{
1436 if ( expr1 && expr1->deref() )
1437 delete expr1;
1438 if ( expr2 && expr2->deref() )
1439 delete expr2;
1440 return Node::deref();
1441}
1442
1443// ECMA 11.10
1444Value BitOperNode::evaluate(ExecState *exec) const
1445{
1446 Value v1 = expr1->evaluate(exec);
1447 KJS_CHECKEXCEPTIONVALUE
1448 Value v2 = expr2->evaluate(exec);
1449 KJS_CHECKEXCEPTIONVALUE
1450 int i1 = v1.toInt32(exec);
1451 int i2 = v2.toInt32(exec);
1452 int result;
1453 if (oper == OpBitAnd)
1454 result = i1 & i2;
1455 else if (oper == OpBitXOr)
1456 result = i1 ^ i2;
1457 else
1458 result = i1 | i2;
1459
1460 return Number(result);
1461}
1462
1463// ----------------------------- BinaryLogicalNode ----------------------------
1464
1465void BinaryLogicalNode::ref()
1466{
1467 Node::ref();
1468 if ( expr1 )
1469 expr1->ref();
1470 if ( expr2 )
1471 expr2->ref();
1472}
1473
1474bool BinaryLogicalNode::deref()
1475{
1476 if ( expr1 && expr1->deref() )
1477 delete expr1;
1478 if ( expr2 && expr2->deref() )
1479 delete expr2;
1480 return Node::deref();
1481}
1482
1483// ECMA 11.11
1484Value BinaryLogicalNode::evaluate(ExecState *exec) const
1485{
1486 Value v1 = expr1->evaluate(exec);
1487 KJS_CHECKEXCEPTIONVALUE
1488 bool b1 = v1.toBoolean(exec);
1489 if ((!b1 && oper == OpAnd) || (b1 && oper == OpOr))
1490 return v1;
1491
1492 Value v2 = expr2->evaluate(exec);
1493 KJS_CHECKEXCEPTIONVALUE
1494
1495 return v2;
1496}
1497
1498// ----------------------------- ConditionalNode ------------------------------
1499
1500void ConditionalNode::ref()
1501{
1502 Node::ref();
1503 if ( expr1 )
1504 expr1->ref();
1505 if ( expr2 )
1506 expr2->ref();
1507 if ( logical )
1508 logical->ref();
1509}
1510
1511bool ConditionalNode::deref()
1512{
1513 if ( expr1 && expr1->deref() )
1514 delete expr1;
1515 if ( expr2 && expr2->deref() )
1516 delete expr2;
1517 if ( logical && logical->deref() )
1518 delete logical;
1519 return Node::deref();
1520}
1521
1522// ECMA 11.12
1523Value ConditionalNode::evaluate(ExecState *exec) const
1524{
1525 bool b = logical->toBoolean(exec);
1526 KJS_CHECKEXCEPTIONVALUE
1527
1528 Value v = b ? expr1->evaluate(exec) : expr2->evaluate(exec);
1529 KJS_CHECKEXCEPTIONVALUE
1530
1531 return v;
1532}
1533
1534// ----------------------------- AssignNode -----------------------------------
1535
1536void AssignNode::ref()
1537{
1538 Node::ref();
1539 if ( left )
1540 left->ref();
1541 if ( expr )
1542 expr->ref();
1543}
1544
1545bool AssignNode::deref()
1546{
1547 if ( left && left->deref() )
1548 delete left;
1549 if ( expr && expr->deref() )
1550 delete expr;
1551 return Node::deref();
1552}
1553
1554// ECMA 11.13
1555Value AssignNode::evaluate(ExecState *exec) const
1556{
1557 Reference l = left->evaluateReference(exec);
1558 KJS_CHECKEXCEPTIONVALUE
1559 Value v;
1560 if (oper == OpEqual) {
1561 v = expr->evaluate(exec);
1562 KJS_CHECKEXCEPTIONVALUE
1563 } else {
1564 Value v1 = l.getValue(exec);
1565 Value v2 = expr->evaluate(exec);
1566 KJS_CHECKEXCEPTIONVALUE
1567 int i1;
1568 int i2;
1569 unsigned int ui;
1570 switch (oper) {
1571 case OpMultEq:
1572 v = mult(exec, v1, v2, '*');
1573 break;
1574 case OpDivEq:
1575 v = mult(exec, v1, v2, '/');
1576 break;
1577 case OpPlusEq:
1578 v = add(exec, v1, v2, '+');
1579 break;
1580 case OpMinusEq:
1581 v = add(exec, v1, v2, '-');
1582 break;
1583 case OpLShift:
1584 i1 = v1.toInt32(exec);
1585 i2 = v2.toInt32(exec);
1586 v = Number(i1 << i2);
1587 break;
1588 case OpRShift:
1589 i1 = v1.toInt32(exec);
1590 i2 = v2.toInt32(exec);
1591 v = Number(i1 >> i2);
1592 break;
1593 case OpURShift:
1594 ui = v1.toUInt32(exec);
1595 i2 = v2.toInt32(exec);
1596 v = Number(ui >> i2);
1597 break;
1598 case OpAndEq:
1599 i1 = v1.toInt32(exec);
1600 i2 = v2.toInt32(exec);
1601 v = Number(i1 & i2);
1602 break;
1603 case OpXOrEq:
1604 i1 = v1.toInt32(exec);
1605 i2 = v2.toInt32(exec);
1606 v = Number(i1 ^ i2);
1607 break;
1608 case OpOrEq:
1609 i1 = v1.toInt32(exec);
1610 i2 = v2.toInt32(exec);
1611 v = Number(i1 | i2);
1612 break;
1613 case OpModEq: {
1614 double d1 = v1.toNumber(exec);
1615 double d2 = v2.toNumber(exec);
1616 v = Number(fmod(d1,d2));
1617 }
1618 break;
1619 default:
1620 v = Undefined();
1621 }
1622 };
1623 l.putValue(exec,v);
1624
1625 KJS_CHECKEXCEPTIONVALUE
1626
1627 return v;
1628}
1629
1630// ----------------------------- CommaNode ------------------------------------
1631
1632void CommaNode::ref()
1633{
1634 Node::ref();
1635 if ( expr1 )
1636 expr1->ref();
1637 if ( expr2 )
1638 expr2->ref();
1639}
1640
1641bool CommaNode::deref()
1642{
1643 if ( expr1 && expr1->deref() )
1644 delete expr1;
1645 if ( expr2 && expr2->deref() )
1646 delete expr2;
1647 return Node::deref();
1648}
1649
1650// ECMA 11.14
1651Value CommaNode::evaluate(ExecState *exec) const
1652{
1653 (void) expr1->evaluate(exec); // ignore return value
1654 KJS_CHECKEXCEPTIONVALUE
1655 Value v = expr2->evaluate(exec);
1656 KJS_CHECKEXCEPTIONVALUE
1657
1658 return v;
1659}
1660
1661// ----------------------------- StatListNode ---------------------------------
1662
1663StatListNode::StatListNode(StatementNode *s)
1664 : statement(s), list(this)
1665{
1666 setLoc(s->firstLine(), s->lastLine(), s->code());
1667}
1668
1669StatListNode::StatListNode(StatListNode *l, StatementNode *s)
1670 : statement(s), list(l->list)
1671{
1672 l->list = this;
1673 setLoc(l->firstLine(),s->lastLine(),l->code());
1674}
1675
1676void StatListNode::ref()
1677{
1678 for (StatListNode *n = this; n; n = n->list) {
1679 n->Node::ref();
1680 if (n->statement)
1681 n->statement->ref();
1682 }
1683}
1684
1685bool StatListNode::deref()
1686{
1687 StatListNode *next;
1688 for (StatListNode *n = this; n; n = next) {
1689 next = n->list;
1690 if (n->statement && n->statement->deref())
1691 delete n->statement;
1692 if (n != this && n->Node::deref())
1693 delete n;
1694 }
1695 return StatementNode::deref();
1696}
1697
1698// ECMA 12.1
1699Completion StatListNode::execute(ExecState *exec)
1700{
1701 Completion c = statement->execute(exec);
1702 KJS_ABORTPOINT
1703 if (exec->hadException()) {
1704 Value ex = exec->exception();
1705 exec->clearException();
1706 return Completion(Throw, ex);
1707 }
1708
1709 if (c.complType() != Normal)
1710 return c;
1711
1712 Value v = c.value();
1713
1714 for (StatListNode *n = list; n; n = n->list) {
1715 Completion c2 = n->statement->execute(exec);
1716 KJS_ABORTPOINT
1717 if (c2.complType() != Normal)
1718 return c2;
1719
1720 if (exec->hadException()) {
1721 Value ex = exec->exception();
1722 exec->clearException();
1723 return Completion(Throw, ex);
1724 }
1725
1726 if (c2.isValueCompletion())
1727 v = c2.value();
1728 c = c2;
1729 }
1730
1731 return Completion(c.complType(), v, c.target());
1732}
1733
1734void StatListNode::processVarDecls(ExecState *exec)
1735{
1736 for (StatListNode *n = this; n; n = n->list)
1737 n->statement->processVarDecls(exec);
1738}
1739
1740// ----------------------------- AssignExprNode -------------------------------
1741
1742void AssignExprNode::ref()
1743{
1744 Node::ref();
1745 if ( expr )
1746 expr->ref();
1747}
1748
1749bool AssignExprNode::deref()
1750{
1751 if ( expr && expr->deref() )
1752 delete expr;
1753 return Node::deref();
1754}
1755
1756// ECMA 12.2
1757Value AssignExprNode::evaluate(ExecState *exec) const
1758{
1759 return expr->evaluate(exec);
1760}
1761
1762// ----------------------------- VarDeclNode ----------------------------------
1763
1764VarDeclNode::VarDeclNode(const Identifier &id, AssignExprNode *in, Type t)
1765 : varType(t), ident(id), init(in)
1766{
1767}
1768
1769void VarDeclNode::ref()
1770{
1771 Node::ref();
1772 if ( init )
1773 init->ref();
1774}
1775
1776bool VarDeclNode::deref()
1777{
1778 if ( init && init->deref() )
1779 delete init;
1780 return Node::deref();
1781}
1782
1783// ECMA 12.2
1784Value VarDeclNode::evaluate(ExecState *exec) const
1785{
1786 Object variable = Object::dynamicCast(exec->context().imp()->variableObject());
1787
1788 Value val;
1789 if (init) {
1790 val = init->evaluate(exec);
1791 KJS_CHECKEXCEPTIONVALUE
1792 } else {
1793 // ### check attributes? reuse check done in processVarDecls()?
1794 if (variable.imp()->getDirect(ident)) // already declared ?
1795 return Value();
1796 val = Undefined();
1797 }
1798
1799#ifdef KJS_VERBOSE
1800 printInfo(exec,(UString("new variable ")+ident.ustring()).cstring().c_str(),val);
1801#endif
1802 // We use Internal to bypass all checks in derived objects, e.g. so that
1803 // "var location" creates a dynamic property instead of activating window.location.
1804 int flags = Internal;
1805 if (exec->context().imp()->codeType() != EvalCode)
1806 flags |= DontDelete;
1807 if (varType == VarDeclNode::Constant)
1808 flags |= ReadOnly;
1809 variable.put(exec, ident, val, flags);
1810
1811 // the spec wants us to return the name of the identifier here
1812 // but we'll save the construction and copying as the return
1813 // value isn't used by the caller
1814 return Value();
1815}
1816
1817void VarDeclNode::processVarDecls(ExecState *exec)
1818{
1819 Object variable = exec->context().variableObject();
1820 // ### use getDirect()? Check attributes?
1821 // ### avoid duplication with actions performed in evaluate()?
1822 if ( !variable.hasProperty( exec, ident ) ) { // already declared ?
1823 int flags = None;
1824 if (exec->_context->codeType() != EvalCode)
1825 flags |= DontDelete;
1826 if (varType == VarDeclNode::Constant)
1827 flags |= ReadOnly;
1828 // TODO: check for forbidden redeclaration of consts
1829 variable.put(exec, ident, Undefined(), flags);
1830 }
1831}
1832
1833// ----------------------------- VarDeclListNode ------------------------------
1834
1835void VarDeclListNode::ref()
1836{
1837 for (VarDeclListNode *n = this; n; n = n->list) {
1838 n->Node::ref();
1839 if (n->var)
1840 n->var->ref();
1841 }
1842}
1843
1844bool VarDeclListNode::deref()
1845{
1846 VarDeclListNode *next;
1847 for (VarDeclListNode *n = this; n; n = next) {
1848 next = n->list;
1849 if (n->var && n->var->deref())
1850 delete n->var;
1851 if (n != this && n->Node::deref())
1852 delete n;
1853 }
1854 return Node::deref();
1855}
1856
1857
1858// ECMA 12.2
1859Value VarDeclListNode::evaluate(ExecState *exec) const
1860{
1861 for (const VarDeclListNode *n = this; n; n = n->list) {
1862 (void)n->var->evaluate(exec);
1863 KJS_CHECKEXCEPTIONVALUE
1864 }
1865 return Undefined();
1866}
1867
1868void VarDeclListNode::processVarDecls(ExecState *exec)
1869{
1870 for (VarDeclListNode *n = this; n; n = n->list)
1871 n->var->processVarDecls(exec);
1872}
1873
1874// ----------------------------- VarStatementNode -----------------------------
1875
1876void VarStatementNode::ref()
1877{
1878 StatementNode::ref();
1879 if ( list )
1880 list->ref();
1881}
1882
1883bool VarStatementNode::deref()
1884{
1885 if ( list && list->deref() )
1886 delete list;
1887 return StatementNode::deref();
1888}
1889
1890// ECMA 12.2
1891Completion VarStatementNode::execute(ExecState *exec)
1892{
1893 KJS_BREAKPOINT;
1894
1895 (void) list->evaluate(exec);
1896 KJS_CHECKEXCEPTION
1897
1898 return Completion(Normal);
1899}
1900
1901void VarStatementNode::processVarDecls(ExecState *exec)
1902{
1903 list->processVarDecls(exec);
1904}
1905
1906// ----------------------------- BlockNode ------------------------------------
1907
1908BlockNode::BlockNode(SourceElementsNode *s)
1909{
1910 if (s) {
1911 source = s->elements;
1912 s->elements = 0;
1913 setLoc(s->firstLine(), s->lastLine(), s->code());
1914 } else {
1915 source = 0;
1916 }
1917}
1918
1919void BlockNode::ref()
1920{
1921 StatementNode::ref();
1922 if ( source )
1923 source->ref();
1924}
1925
1926bool BlockNode::deref()
1927{
1928 if ( source && source->deref() )
1929 delete source;
1930 return StatementNode::deref();
1931}
1932
1933// ECMA 12.1
1934Completion BlockNode::execute(ExecState *exec)
1935{
1936 if (!source)
1937 return Completion(Normal);
1938
1939 source->processFuncDecl(exec);
1940
1941 return source->execute(exec);
1942}
1943
1944void BlockNode::processVarDecls(ExecState *exec)
1945{
1946 if (source)
1947 source->processVarDecls(exec);
1948}
1949
1950// ----------------------------- EmptyStatementNode ---------------------------
1951
1952// ECMA 12.3
1953Completion EmptyStatementNode::execute(ExecState * /*exec*/)
1954{
1955 return Completion(Normal);
1956}
1957
1958// ----------------------------- ExprStatementNode ----------------------------
1959
1960void ExprStatementNode::ref()
1961{
1962 StatementNode::ref();
1963 if ( expr )
1964 expr->ref();
1965}
1966
1967bool ExprStatementNode::deref()
1968{
1969 if ( expr && expr->deref() )
1970 delete expr;
1971 return StatementNode::deref();
1972}
1973
1974// ECMA 12.4
1975Completion ExprStatementNode::execute(ExecState *exec)
1976{
1977 KJS_BREAKPOINT;
1978
1979 Value v = expr->evaluate(exec);
1980 KJS_CHECKEXCEPTION
1981
1982 return Completion(Normal, v);
1983}
1984
1985// ----------------------------- IfNode ---------------------------------------
1986
1987void IfNode::ref()
1988{
1989 StatementNode::ref();
1990 if ( statement1 )
1991 statement1->ref();
1992 if ( statement2 )
1993 statement2->ref();
1994 if ( expr )
1995 expr->ref();
1996}
1997
1998bool IfNode::deref()
1999{
2000 if ( statement1 && statement1->deref() )
2001 delete statement1;
2002 if ( statement2 && statement2->deref() )
2003 delete statement2;
2004 if ( expr && expr->deref() )
2005 delete expr;
2006 return StatementNode::deref();
2007}
2008
2009// ECMA 12.5
2010Completion IfNode::execute(ExecState *exec)
2011{
2012 KJS_BREAKPOINT;
2013
2014 assert(expr);
2015 bool b = expr->toBoolean(exec);
2016 KJS_CHECKEXCEPTION
2017
2018 // if ... then
2019 if (b)
2020 return statement1->execute(exec);
2021
2022 // no else
2023 if (!statement2)
2024 return Completion(Normal);
2025
2026 // else
2027 return statement2->execute(exec);
2028}
2029
2030void IfNode::processVarDecls(ExecState *exec)
2031{
2032 statement1->processVarDecls(exec);
2033
2034 if (statement2)
2035 statement2->processVarDecls(exec);
2036}
2037
2038// ----------------------------- DoWhileNode ----------------------------------
2039
2040void DoWhileNode::ref()
2041{
2042 StatementNode::ref();
2043 if ( statement )
2044 statement->ref();
2045 if ( expr )
2046 expr->ref();
2047}
2048
2049bool DoWhileNode::deref()
2050{
2051 if ( statement && statement->deref() )
2052 delete statement;
2053 if ( expr && expr->deref() )
2054 delete expr;
2055 return StatementNode::deref();
2056}
2057
2058// ECMA 12.6.1
2059Completion DoWhileNode::execute(ExecState *exec)
2060{
2061 KJS_BREAKPOINT;
2062
2063 Completion c;
2064 Value value;
2065 bool b;
2066
2067 do {
2068 // bail out on error
2069 KJS_CHECKEXCEPTION
2070
2071 exec->context().imp()->seenLabels()->pushIteration();
2072 c = statement->execute(exec);
2073 exec->context().imp()->seenLabels()->popIteration();
2074 if (!((c.complType() == Continue) && ls.contains(c.target()))) {
2075 if ((c.complType() == Break) && ls.contains(c.target()))
2076 return Completion(Normal, value);
2077 if (c.complType() != Normal)
2078 return c;
2079 }
2080 b = expr->toBoolean(exec);
2081 KJS_CHECKEXCEPTION
2082 } while (b);
2083
2084 return Completion(Normal, value);
2085}
2086
2087void DoWhileNode::processVarDecls(ExecState *exec)
2088{
2089 statement->processVarDecls(exec);
2090}
2091
2092// ----------------------------- WhileNode ------------------------------------
2093
2094void WhileNode::ref()
2095{
2096 StatementNode::ref();
2097 if ( statement )
2098 statement->ref();
2099 if ( expr )
2100 expr->ref();
2101}
2102
2103bool WhileNode::deref()
2104{
2105 if ( statement && statement->deref() )
2106 delete statement;
2107 if ( expr && expr->deref() )
2108 delete expr;
2109 return StatementNode::deref();
2110}
2111
2112// ECMA 12.6.2
2113Completion WhileNode::execute(ExecState *exec)
2114{
2115 KJS_BREAKPOINT;
2116
2117 Completion c;
2118 Value value;
2119
2120 while (1) {
2121 bool b = expr->toBoolean(exec);
2122 KJS_CHECKEXCEPTION
2123
2124 // bail out on error
2125 KJS_CHECKEXCEPTION
2126
2127 if (!b)
2128 return Completion(Normal, value);
2129
2130 exec->context().imp()->seenLabels()->pushIteration();
2131 c = statement->execute(exec);
2132 exec->context().imp()->seenLabels()->popIteration();
2133 if (c.isValueCompletion())
2134 value = c.value();
2135
2136 if ((c.complType() == Continue) && ls.contains(c.target()))
2137 continue;
2138 if ((c.complType() == Break) && ls.contains(c.target()))
2139 return Completion(Normal, value);
2140 if (c.complType() != Normal)
2141 return c;
2142 }
2143}
2144
2145void WhileNode::processVarDecls(ExecState *exec)
2146{
2147 statement->processVarDecls(exec);
2148}
2149
2150// ----------------------------- ForNode --------------------------------------
2151
2152void ForNode::ref()
2153{
2154 StatementNode::ref();
2155 if ( statement )
2156 statement->ref();
2157 if ( expr1 )
2158 expr1->ref();
2159 if ( expr2 )
2160 expr2->ref();
2161 if ( expr3 )
2162 expr3->ref();
2163}
2164
2165bool ForNode::deref()
2166{
2167 if ( statement && statement->deref() )
2168 delete statement;
2169 if ( expr1 && expr1->deref() )
2170 delete expr1;
2171 if ( expr2 && expr2->deref() )
2172 delete expr2;
2173 if ( expr3 && expr3->deref() )
2174 delete expr3;
2175 return StatementNode::deref();
2176}
2177
2178// ECMA 12.6.3
2179Completion ForNode::execute(ExecState *exec)
2180{
2181 Value v, cval;
2182
2183 if (expr1) {
2184 v = expr1->evaluate(exec);
2185 KJS_CHECKEXCEPTION
2186 }
2187 for (;;) {
2188 if (expr2) {
2189 bool b = expr2->toBoolean(exec);
2190 KJS_CHECKEXCEPTION
2191 if (!b)
2192 return Completion(Normal, cval);
2193 }
2194 // bail out on error
2195 KJS_CHECKEXCEPTION
2196
2197 exec->context().imp()->seenLabels()->pushIteration();
2198 Completion c = statement->execute(exec);
2199 exec->context().imp()->seenLabels()->popIteration();
2200 if (c.isValueCompletion())
2201 cval = c.value();
2202 if (!((c.complType() == Continue) && ls.contains(c.target()))) {
2203 if ((c.complType() == Break) && ls.contains(c.target()))
2204 return Completion(Normal, cval);
2205 if (c.complType() != Normal)
2206 return c;
2207 }
2208 if (expr3) {
2209 v = expr3->evaluate(exec);
2210 KJS_CHECKEXCEPTION
2211 }
2212 }
2213}
2214
2215void ForNode::processVarDecls(ExecState *exec)
2216{
2217 if (expr1)
2218 expr1->processVarDecls(exec);
2219
2220 statement->processVarDecls(exec);
2221}
2222
2223// ----------------------------- ForInNode ------------------------------------
2224
2225ForInNode::ForInNode(Node *l, Node *e, StatementNode *s)
2226 : init(0L), lexpr(l), expr(e), varDecl(0L), statement(s)
2227{
2228}
2229
2230ForInNode::ForInNode(const Identifier &i, AssignExprNode *in, Node *e, StatementNode *s)
2231 : ident(i), init(in), expr(e), statement(s)
2232{
2233 // for( var foo = bar in baz )
2234 varDecl = new VarDeclNode(ident, init, VarDeclNode::Variable);
2235 lexpr = new ResolveNode(ident);
2236}
2237
2238void ForInNode::ref()
2239{
2240 StatementNode::ref();
2241 if ( statement )
2242 statement->ref();
2243 if ( expr )
2244 expr->ref();
2245 if ( lexpr )
2246 lexpr->ref();
2247 if ( init )
2248 init->ref();
2249 if ( varDecl )
2250 varDecl->ref();
2251}
2252
2253bool ForInNode::deref()
2254{
2255 if ( statement && statement->deref() )
2256 delete statement;
2257 if ( expr && expr->deref() )
2258 delete expr;
2259 if ( lexpr && lexpr->deref() )
2260 delete lexpr;
2261 if ( init && init->deref() )
2262 delete init;
2263 if ( varDecl && varDecl->deref() )
2264 delete varDecl;
2265 return StatementNode::deref();
2266}
2267
2268// ECMA 12.6.4
2269Completion ForInNode::execute(ExecState *exec)
2270{
2271 Value retval;
2272 Completion c;
2273
2274 if ( varDecl ) {
2275 (void)varDecl->evaluate(exec);
2276 KJS_CHECKEXCEPTION
2277 }
2278
2279 Value v = expr->evaluate(exec);
2280 // for Null and Undefined, we want to make sure not to go through
2281 // the loop at all, because their object wrappers will have a
2282 // property list but will throw an exception if you attempt to
2283 // access any property.
2284 if (v.isA(NullType) || v.isA(UndefinedType))
2285 return Completion(Normal, retval);
2286
2287 Object o = v.toObject(exec);
2288 KJS_CHECKEXCEPTION
2289 ReferenceList propList = o.propList(exec);
2290
2291 ReferenceListIterator propIt = propList.begin();
2292
2293 while (propIt != propList.end()) {
2294 Identifier name = propIt->getPropertyName(exec);
2295 if (!o.hasProperty(exec,name)) {
2296 propIt++;
2297 continue;
2298 }
2299
2300 Reference ref = lexpr->evaluateReference(exec);
2301 KJS_CHECKEXCEPTION
2302 ref.putValue(exec, String(name.ustring()));
2303
2304 exec->context().imp()->seenLabels()->pushIteration();
2305 c = statement->execute(exec);
2306 exec->context().imp()->seenLabels()->popIteration();
2307 if (c.isValueCompletion())
2308 retval = c.value();
2309
2310 if (!((c.complType() == Continue) && ls.contains(c.target()))) {
2311 if ((c.complType() == Break) && ls.contains(c.target()))
2312 break;
2313 if (c.complType() != Normal) {
2314 return c;
2315 }
2316 }
2317
2318 propIt++;
2319 }
2320
2321 // bail out on error
2322 KJS_CHECKEXCEPTION
2323
2324 return Completion(Normal, retval);
2325}
2326
2327void ForInNode::processVarDecls(ExecState *exec)
2328{
2329 statement->processVarDecls(exec);
2330}
2331
2332// ----------------------------- ContinueNode ---------------------------------
2333
2334// ECMA 12.7
2335Completion ContinueNode::execute(ExecState *exec)
2336{
2337 KJS_BREAKPOINT;
2338
2339 Value dummy;
2340
2341 if (ident.isEmpty() && !exec->context().imp()->seenLabels()->inIteration())
2342 return Completion(Throw,
2343 throwError(exec, SyntaxError, "continue used outside of iteration statement"));
2344 else if (!ident.isEmpty() && !exec->context().imp()->seenLabels()->contains(ident))
2345 return Completion(Throw,
2346 throwError(exec, SyntaxError, "Label %s not found in containing block. Can't continue.", ident));
2347 else
2348 return Completion(Continue, dummy, ident);
2349}
2350
2351// ----------------------------- BreakNode ------------------------------------
2352
2353// ECMA 12.8
2354Completion BreakNode::execute(ExecState *exec)
2355{
2356 KJS_BREAKPOINT;
2357
2358 Value dummy;
2359
2360 if (ident.isEmpty() && !exec->context().imp()->seenLabels()->inIteration() &&
2361 !exec->context().imp()->seenLabels()->inSwitch())
2362 return Completion(Throw,
2363 throwError(exec, SyntaxError, "break used outside of iteration or switch statement"));
2364 else if (!ident.isEmpty() && !exec->context().imp()->seenLabels()->contains(ident))
2365 return Completion(Throw,
2366 throwError(exec, SyntaxError, "Label %s not found in containing block. Can't break.", ident));
2367 else
2368 return Completion(Break, dummy, ident);
2369}
2370
2371// ----------------------------- ReturnNode -----------------------------------
2372
2373void ReturnNode::ref()
2374{
2375 StatementNode::ref();
2376 if ( value )
2377 value->ref();
2378}
2379
2380bool ReturnNode::deref()
2381{
2382 if ( value && value->deref() )
2383 delete value;
2384 return StatementNode::deref();
2385}
2386
2387// ECMA 12.9
2388Completion ReturnNode::execute(ExecState *exec)
2389{
2390 KJS_BREAKPOINT;
2391
2392 CodeType codeType = exec->context().imp()->codeType();
2393 if (codeType != FunctionCode) {
2394 return Completion(Throw, throwError(exec, SyntaxError, "Invalid return statement."));
2395 }
2396
2397 if (!value)
2398 return Completion(ReturnValue, Undefined());
2399
2400 Value v = value->evaluate(exec);
2401 KJS_CHECKEXCEPTION
2402
2403 return Completion(ReturnValue, v);
2404}
2405
2406// ----------------------------- WithNode -------------------------------------
2407
2408void WithNode::ref()
2409{
2410 StatementNode::ref();
2411 if ( statement )
2412 statement->ref();
2413 if ( expr )
2414 expr->ref();
2415}
2416
2417bool WithNode::deref()
2418{
2419 if ( statement && statement->deref() )
2420 delete statement;
2421 if ( expr && expr->deref() )
2422 delete expr;
2423 return StatementNode::deref();
2424}
2425
2426// ECMA 12.10
2427Completion WithNode::execute(ExecState *exec)
2428{
2429 KJS_BREAKPOINT;
2430
2431 Value v = expr->evaluate(exec);
2432 KJS_CHECKEXCEPTION
2433 Object o = v.toObject(exec);
2434 KJS_CHECKEXCEPTION
2435 exec->context().imp()->pushScope(o);
2436 Completion res = statement->execute(exec);
2437 exec->context().imp()->popScope();
2438
2439 return res;
2440}
2441
2442void WithNode::processVarDecls(ExecState *exec)
2443{
2444 statement->processVarDecls(exec);
2445}
2446
2447// ----------------------------- CaseClauseNode -------------------------------
2448
2449void CaseClauseNode::ref()
2450{
2451 Node::ref();
2452 if ( expr )
2453 expr->ref();
2454 if ( list )
2455 list->ref();
2456}
2457
2458bool CaseClauseNode::deref()
2459{
2460 if ( expr && expr->deref() )
2461 delete expr;
2462 if ( list && list->deref() )
2463 delete list;
2464 return Node::deref();
2465}
2466
2467// ECMA 12.11
2468Value CaseClauseNode::evaluate(ExecState *exec) const
2469{
2470 Value v = expr->evaluate(exec);
2471 KJS_CHECKEXCEPTIONVALUE
2472
2473 return v;
2474}
2475
2476// ECMA 12.11
2477Completion CaseClauseNode::evalStatements(ExecState *exec) const
2478{
2479 if (list)
2480 return list->execute(exec);
2481 else
2482 return Completion(Normal, Undefined());
2483}
2484
2485void CaseClauseNode::processVarDecls(ExecState *exec)
2486{
2487 if (list)
2488 list->processVarDecls(exec);
2489}
2490
2491// ----------------------------- ClauseListNode -------------------------------
2492
2493void ClauseListNode::ref()
2494{
2495 for (ClauseListNode *n = this; n; n = n->nx) {
2496 n->Node::ref();
2497 if (n->cl)
2498 n->cl->ref();
2499 }
2500}
2501
2502bool ClauseListNode::deref()
2503{
2504 ClauseListNode *next;
2505 for (ClauseListNode *n = this; n; n = next) {
2506 next = n->nx;
2507 if (n->cl && n->cl->deref())
2508 delete n->cl;
2509 if (n != this && n->Node::deref())
2510 delete n;
2511 }
2512 return Node::deref();
2513}
2514
2515Value ClauseListNode::evaluate(ExecState * /*exec*/) const
2516{
2517 /* should never be called */
2518 assert(false);
2519 return Value();
2520}
2521
2522// ECMA 12.11
2523void ClauseListNode::processVarDecls(ExecState *exec)
2524{
2525 for (ClauseListNode *n = this; n; n = n->nx)
2526 if (n->cl)
2527 n->cl->processVarDecls(exec);
2528}
2529
2530// ----------------------------- CaseBlockNode --------------------------------
2531
2532CaseBlockNode::CaseBlockNode(ClauseListNode *l1, CaseClauseNode *d,
2533 ClauseListNode *l2)
2534{
2535 def = d;
2536 if (l1) {
2537 list1 = l1->nx;
2538 l1->nx = 0;
2539 } else {
2540 list1 = 0;
2541 }
2542 if (l2) {
2543 list2 = l2->nx;
2544 l2->nx = 0;
2545 } else {
2546 list2 = 0;
2547 }
2548}
2549
2550void CaseBlockNode::ref()
2551{
2552 Node::ref();
2553 if ( def )
2554 def->ref();
2555 if ( list1 )
2556 list1->ref();
2557 if ( list2 )
2558 list2->ref();
2559}
2560
2561bool CaseBlockNode::deref()
2562{
2563 if ( def && def->deref() )
2564 delete def;
2565 if ( list1 && list1->deref() )
2566 delete list1;
2567 if ( list2 && list2->deref() )
2568 delete list2;
2569 return Node::deref();
2570}
2571
2572Value CaseBlockNode::evaluate(ExecState * /*exec*/) const
2573{
2574 /* should never be called */
2575 assert(false);
2576 return Value();
2577}
2578
2579// ECMA 12.11
2580Completion CaseBlockNode::evalBlock(ExecState *exec, const Value& input) const
2581{
2582 Value v;
2583 Completion res;
2584 ClauseListNode *a = list1, *b = list2;
2585 CaseClauseNode *clause;
2586
2587 while (a) {
2588 clause = a->clause();
2589 a = a->next();
2590 v = clause->evaluate(exec);
2591 KJS_CHECKEXCEPTION
2592 if (strictEqual(exec, input, v)) {
2593 res = clause->evalStatements(exec);
2594 if (res.complType() != Normal)
2595 return res;
2596 while (a) {
2597 res = a->clause()->evalStatements(exec);
2598 if (res.complType() != Normal)
2599 return res;
2600 a = a->next();
2601 }
2602 break;
2603 }
2604 }
2605
2606 while (b) {
2607 clause = b->clause();
2608 b = b->next();
2609 v = clause->evaluate(exec);
2610 KJS_CHECKEXCEPTION
2611 if (strictEqual(exec, input, v)) {
2612 res = clause->evalStatements(exec);
2613 if (res.complType() != Normal)
2614 return res;
2615 goto step18;
2616 }
2617 }
2618
2619 // default clause
2620 if (def) {
2621 res = def->evalStatements(exec);
2622 if (res.complType() != Normal)
2623 return res;
2624 }
2625 b = list2;
2626 step18:
2627 while (b) {
2628 clause = b->clause();
2629 res = clause->evalStatements(exec);
2630 if (res.complType() != Normal)
2631 return res;
2632 b = b->next();
2633 }
2634
2635 // bail out on error
2636 KJS_CHECKEXCEPTION
2637
2638 return Completion(Normal);
2639}
2640
2641void CaseBlockNode::processVarDecls(ExecState *exec)
2642{
2643 if (list1)
2644 list1->processVarDecls(exec);
2645 if (def)
2646 def->processVarDecls(exec);
2647 if (list2)
2648 list2->processVarDecls(exec);
2649}
2650
2651// ----------------------------- SwitchNode -----------------------------------
2652
2653void SwitchNode::ref()
2654{
2655 StatementNode::ref();
2656 if ( expr )
2657 expr->ref();
2658 if ( block )
2659 block->ref();
2660}
2661
2662bool SwitchNode::deref()
2663{
2664 if ( expr && expr->deref() )
2665 delete expr;
2666 if ( block && block->deref() )
2667 delete block;
2668 return StatementNode::deref();
2669}
2670
2671// ECMA 12.11
2672Completion SwitchNode::execute(ExecState *exec)
2673{
2674 KJS_BREAKPOINT;
2675
2676 Value v = expr->evaluate(exec);
2677 KJS_CHECKEXCEPTION
2678 exec->context().imp()->seenLabels()->pushSwitch();
2679 Completion res = block->evalBlock(exec,v);
2680 exec->context().imp()->seenLabels()->popSwitch();
2681
2682 if ((res.complType() == Break) && ls.contains(res.target()))
2683 return Completion(Normal, res.value());
2684 else
2685 return res;
2686}
2687
2688void SwitchNode::processVarDecls(ExecState *exec)
2689{
2690 block->processVarDecls(exec);
2691}
2692
2693// ----------------------------- LabelNode ------------------------------------
2694
2695void LabelNode::ref()
2696{
2697 StatementNode::ref();
2698 if ( statement )
2699 statement->ref();
2700}
2701
2702bool LabelNode::deref()
2703{
2704 if ( statement && statement->deref() )
2705 delete statement;
2706 return StatementNode::deref();
2707}
2708
2709// ECMA 12.12
2710Completion LabelNode::execute(ExecState *exec)
2711{
2712 Completion e;
2713
2714 if (!exec->context().imp()->seenLabels()->push(label)) {
2715 return Completion( Throw,
2716 throwError(exec, SyntaxError, "Duplicated label %s found.", label));
2717 };
2718 e = statement->execute(exec);
2719 exec->context().imp()->seenLabels()->pop();
2720
2721 if ((e.complType() == Break) && (e.target() == label))
2722 return Completion(Normal, e.value());
2723 else
2724 return e;
2725}
2726
2727void LabelNode::processVarDecls(ExecState *exec)
2728{
2729 statement->processVarDecls(exec);
2730}
2731
2732// ----------------------------- ThrowNode ------------------------------------
2733
2734void ThrowNode::ref()
2735{
2736 StatementNode::ref();
2737 if ( expr )
2738 expr->ref();
2739}
2740
2741bool ThrowNode::deref()
2742{
2743 if ( expr && expr->deref() )
2744 delete expr;
2745 return StatementNode::deref();
2746}
2747
2748// ECMA 12.13
2749Completion ThrowNode::execute(ExecState *exec)
2750{
2751 KJS_BREAKPOINT;
2752
2753 Value v = expr->evaluate(exec);
2754 KJS_CHECKEXCEPTION
2755
2756 // bail out on error
2757 KJS_CHECKEXCEPTION
2758
2759 Debugger *dbg = exec->interpreter()->imp()->debugger();
2760 if (dbg)
2761 dbg->exception(exec,v,exec->context().imp()->inTryCatch());
2762
2763 return Completion(Throw, v);
2764}
2765
2766// ----------------------------- CatchNode ------------------------------------
2767
2768void CatchNode::ref()
2769{
2770 StatementNode::ref();
2771 if ( block )
2772 block->ref();
2773}
2774
2775bool CatchNode::deref()
2776{
2777 if ( block && block->deref() )
2778 delete block;
2779 return StatementNode::deref();
2780}
2781
2782Completion CatchNode::execute(ExecState * /*exec*/)
2783{
2784 // should never be reached. execute(exec, arg) is used instead
2785 assert(0L);
2786 return Completion();
2787}
2788
2789// ECMA 12.14
2790Completion CatchNode::execute(ExecState *exec, const Value &arg)
2791{
2792 /* TODO: correct ? Not part of the spec */
2793
2794 exec->clearException();
2795
2796 Object obj(new ObjectImp());
2797 obj.put(exec, ident, arg, DontDelete);
2798 exec->context().imp()->pushScope(obj);
2799 Completion c = block->execute(exec);
2800 exec->context().imp()->popScope();
2801
2802 return c;
2803}
2804
2805void CatchNode::processVarDecls(ExecState *exec)
2806{
2807 block->processVarDecls(exec);
2808}
2809
2810// ----------------------------- FinallyNode ----------------------------------
2811
2812void FinallyNode::ref()
2813{
2814 StatementNode::ref();
2815 if ( block )
2816 block->ref();
2817}
2818
2819bool FinallyNode::deref()
2820{
2821 if ( block && block->deref() )
2822 delete block;
2823 return StatementNode::deref();
2824}
2825
2826// ECMA 12.14
2827Completion FinallyNode::execute(ExecState *exec)
2828{
2829 return block->execute(exec);
2830}
2831
2832void FinallyNode::processVarDecls(ExecState *exec)
2833{
2834 block->processVarDecls(exec);
2835}
2836
2837// ----------------------------- TryNode --------------------------------------
2838
2839void TryNode::ref()
2840{
2841 StatementNode::ref();
2842 if ( block )
2843 block->ref();
2844 if ( _final )
2845 _final->ref();
2846 if ( _catch )
2847 _catch->ref();
2848}
2849
2850bool TryNode::deref()
2851{
2852 if ( block && block->deref() )
2853 delete block;
2854 if ( _final && _final->deref() )
2855 delete _final;
2856 if ( _catch && _catch->deref() )
2857 delete _catch;
2858 return StatementNode::deref();
2859}
2860
2861// ECMA 12.14
2862Completion TryNode::execute(ExecState *exec)
2863{
2864 KJS_BREAKPOINT;
2865
2866 Completion c, c2;
2867
2868 if (_catch)
2869 exec->context().imp()->pushTryCatch();
2870 c = block->execute(exec);
2871 if (_catch)
2872 exec->context().imp()->popTryCatch();
2873
2874 if (!_final) {
2875 if (c.complType() != Throw)
2876 return c;
2877 return _catch->execute(exec,c.value());
2878 }
2879
2880 if (!_catch) {
2881 Value exception = exec->_exception;
2882 exec->_exception = Value();
2883
2884 c2 = _final->execute(exec);
2885
2886 if (!exec->hadException() && c2.complType() != Throw)
2887 exec->_exception = exception;
2888
2889 return (c2.complType() == Normal) ? c : c2;
2890 }
2891
2892 if (c.complType() == Throw)
2893 c = _catch->execute(exec,c.value());
2894
2895 c2 = _final->execute(exec);
2896 return (c2.complType() == Normal) ? c : c2;
2897}
2898
2899void TryNode::processVarDecls(ExecState *exec)
2900{
2901 block->processVarDecls(exec);
2902 if (_final)
2903 _final->processVarDecls(exec);
2904 if (_catch)
2905 _catch->processVarDecls(exec);
2906}
2907
2908// ----------------------------- ParameterNode --------------------------------
2909
2910void ParameterNode::ref()
2911{
2912 for (ParameterNode *n = this; n; n = n->next)
2913 n->Node::ref();
2914}
2915
2916bool ParameterNode::deref()
2917{
2918 ParameterNode *next;
2919 for (ParameterNode *n = this; n; n = next) {
2920 next = n->next;
2921 if (n != this && n->Node::deref())
2922 delete n;
2923 }
2924 return Node::deref();
2925}
2926
2927// ECMA 13
2928Value ParameterNode::evaluate(ExecState * /*exec*/) const
2929{
2930 return Undefined();
2931}
2932
2933// ----------------------------- FunctionBodyNode -----------------------------
2934
2935
2936FunctionBodyNode::FunctionBodyNode(SourceElementsNode *s)
2937 : BlockNode(s)
2938{
2939 //fprintf(stderr,"FunctionBodyNode::FunctionBodyNode %p\n",this);
2940}
2941
2942void FunctionBodyNode::processFuncDecl(ExecState *exec)
2943{
2944 if (source)
2945 source->processFuncDecl(exec);
2946}
2947
2948// ----------------------------- FuncDeclNode ---------------------------------
2949
2950void FuncDeclNode::ref()
2951{
2952 StatementNode::ref();
2953 if ( param )
2954 param->ref();
2955 if ( body )
2956 body->ref();
2957}
2958
2959bool FuncDeclNode::deref()
2960{
2961 if ( param && param->deref() )
2962 delete param;
2963 if ( body && body->deref() )
2964 delete body;
2965 return StatementNode::deref();
2966}
2967
2968// ECMA 13
2969void FuncDeclNode::processFuncDecl(ExecState *exec)
2970{
2971 ContextImp *ctx = exec->context().imp();
2972 // TODO: let this be an object with [[Class]] property "Function"
2973 FunctionImp *fimp = new DeclaredFunctionImp(exec, ident, body, exec->context().imp()->scopeChain());
2974 Object func(fimp); // protect from GC
2975
2976 // Value proto = exec->lexicalInterpreter()->builtinObject().construct(exec,List::empty());
2977 List empty;
2978 Object proto = exec->lexicalInterpreter()->builtinObject().construct(exec,empty);
2979 proto.put(exec, constructorPropertyName, func, ReadOnly|DontDelete|DontEnum);
2980 func.put(exec, prototypePropertyName, proto, Internal|DontDelete);
2981
2982 int plen = 0;
2983 for(const ParameterNode *p = param; p != 0L; p = p->nextParam(), plen++)
2984 fimp->addParameter(p->ident());
2985
2986 func.put(exec, lengthPropertyName, Number(plen), ReadOnly|DontDelete|DontEnum);
2987
2988#ifdef KJS_VERBOSE
2989 fprintf(stderr,"KJS: new function %s in %p\n", ident.ustring().cstring().c_str(), ctx->variableObject().imp());
2990#endif
2991 if (exec->_context->codeType() == EvalCode) {
2992 // ECMA 10.2.2
2993 ctx->variableObject().put(exec, ident, func, Internal);
2994 } else {
2995 ctx->variableObject().put(exec, ident, func, DontDelete | Internal);
2996 }
2997
2998 if (body) {
2999 // hack the scope so that the function gets put as a property of func, and it's scope
3000 // contains the func as well as our current scope
3001 Object oldVar = ctx->variableObject();
3002 ctx->setVariableObject(func);
3003 ctx->pushScope(func);
3004 body->processFuncDecl(exec);
3005 ctx->popScope();
3006 ctx->setVariableObject(oldVar);
3007 }
3008}
3009
3010// ----------------------------- FuncExprNode ---------------------------------
3011
3012void FuncExprNode::ref()
3013{
3014 Node::ref();
3015 if ( param )
3016 param->ref();
3017 if ( body )
3018 body->ref();
3019}
3020
3021bool FuncExprNode::deref()
3022{
3023 if ( param && param->deref() )
3024 delete param;
3025 if ( body && body->deref() )
3026 delete body;
3027 return Node::deref();
3028}
3029
3030
3031// ECMA 13
3032Value FuncExprNode::evaluate(ExecState *exec) const
3033{
3034 ContextImp *context = exec->context().imp();
3035 bool named = !ident.isNull();
3036 Object functionScopeObject;
3037
3038 if (named) {
3039 // named FunctionExpressions can recursively call themselves,
3040 // but they won't register with the current scope chain and should
3041 // be contained as single property in an anonymous object.
3042 functionScopeObject = Object(new ObjectImp());
3043 context->pushScope(functionScopeObject);
3044 }
3045
3046 FunctionImp *fimp = new DeclaredFunctionImp(exec, Identifier::null(), body, exec->context().imp()->scopeChain());
3047 Value ret(fimp);
3048 List empty;
3049 Value proto = exec->lexicalInterpreter()->builtinObject().construct(exec,empty);
3050 fimp->put(exec, prototypePropertyName, proto, Internal|DontDelete);
3051
3052 for(const ParameterNode *p = param; p != 0L; p = p->nextParam())
3053 fimp->addParameter(p->ident());
3054
3055 if (named) {
3056 functionScopeObject.put(exec, ident, Value(fimp), ReadOnly|DontDelete);
3057 context->popScope();
3058 }
3059
3060 return ret;
3061}
3062
3063// ----------------------------- SourceElementsNode ---------------------------
3064
3065SourceElementsNode::SourceElementsNode(StatementNode *s1)
3066{
3067 element = s1;
3068 elements = this;
3069 setLoc(s1->firstLine(), s1->lastLine(), s1->code());
3070}
3071
3072SourceElementsNode::SourceElementsNode(SourceElementsNode *s1, StatementNode *s2)
3073{
3074 elements = s1->elements;
3075 s1->elements = this;
3076 element = s2;
3077 setLoc(s1->firstLine(), s2->lastLine(), s1->code());
3078}
3079
3080void SourceElementsNode::ref()
3081{
3082 for (SourceElementsNode *n = this; n; n = n->elements) {
3083 n->Node::ref();
3084 if (n->element)
3085 n->element->ref();
3086 }
3087}
3088
3089bool SourceElementsNode::deref()
3090{
3091 SourceElementsNode *next;
3092 for (SourceElementsNode *n = this; n; n = next) {
3093 next = n->elements;
3094 if (n->element && n->element->deref())
3095 delete n->element;
3096 if (n != this && n->Node::deref())
3097 delete n;
3098 }
3099 return StatementNode::deref();
3100}
3101
3102// ECMA 14
3103Completion SourceElementsNode::execute(ExecState *exec)
3104{
3105 KJS_CHECKEXCEPTION
3106
3107 Completion c1 = element->execute(exec);
3108 KJS_CHECKEXCEPTION;
3109 if (c1.complType() != Normal)
3110 return c1;
3111
3112 for (SourceElementsNode *n = elements; n; n = n->elements) {
3113 Completion c2 = n->element->execute(exec);
3114 if (c2.complType() != Normal)
3115 return c2;
3116 // The spec says to return c2 here, but it seems that mozilla returns c1 if
3117 // c2 doesn't have a value
3118 if (c2.value().isValid())
3119 c1 = c2;
3120 }
3121
3122 return c1;
3123}
3124
3125// ECMA 14
3126void SourceElementsNode::processFuncDecl(ExecState *exec)
3127{
3128 for (SourceElementsNode *n = this; n; n = n->elements)
3129 n->element->processFuncDecl(exec);
3130}
3131
3132void SourceElementsNode::processVarDecls(ExecState *exec)
3133{
3134 for (SourceElementsNode *n = this; n; n = n->elements)
3135 n->element->processVarDecls(exec);
3136}
KJS::Boolean
Represents an primitive Boolean value.
Definition: value.h:316
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::Context::variableObject
Object variableObject() const
Returns the variable object for the execution context.
Definition: interpreter.cpp:50
KJS::ExecState
Represents the current state of script execution.
Definition: interpreter.h:438
KJS::ExecState::context
Context context() const
Returns the execution context associated with this execution state.
Definition: interpreter.h:470
KJS::ExecState::dynamicInterpreter
Interpreter * dynamicInterpreter() const
Returns the interpreter associated with this execution state.
Definition: interpreter.h:452
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::Identifier
Represents an Identifier for a Javascript object.
Definition: identifier.h:32
KJS::Interpreter::builtinObject
Object builtinObject() const
Returns the builtin "Object" object.
Definition: interpreter.cpp:173
KJS::Interpreter::builtinArray
Object builtinArray() const
Returns the builtin "Array" object.
Definition: interpreter.cpp:183
KJS::Interpreter::globalObject
Object & globalObject() const
Returns the object that is used as the global object during all script execution performed by this in...
Definition: interpreter.cpp:128
KJS::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::Null
Represents an primitive Null value.
Definition: value.h:294
KJS::Number
Represents an primitive Number value.
Definition: value.h:367
KJS::Object
Represents an Object.
Definition: object.h:81
KJS::Object::implementsCall
bool implementsCall() const
Whether or not the object implements the call() method.
Definition: object.h:699
KJS::Object::implementsConstruct
bool implementsConstruct() const
Whether or not the object implements the construct() method.
Definition: object.h:693
KJS::Object::construct
Object construct(ExecState *exec, const List &args)
Creates a new object based on this object.
Definition: object.h:696
KJS::Object::propList
ReferenceList propList(ExecState *exec, bool recursive=true)
Returns a List of References to all the properties of the object.
Definition: object.h:714
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::call
Value call(ExecState *exec, Object &thisObj, const List &args)
Calls this object as if it is a function.
Definition: object.cpp:53
KJS::Object::hasProperty
bool hasProperty(ExecState *exec, const Identifier &propertyName) const
Checks to see whether the object (or any object in it's prototype chain) has a property with the spec...
Definition: object.h:678
KJS::Object::get
Value get(ExecState *exec, const Identifier &propertyName) const
Retrieves the specified property from the object.
Definition: object.h:663
KJS::ReferenceListIterator
An iterator for a ReferenceList.
Definition: reference_list.h:36
KJS::ReferenceList
A list of Reference objects.
Definition: reference_list.h:53
KJS::Reference
Defines a Javascript reference.
Definition: reference.h:34
KJS::Reference::getPropertyName
Identifier getPropertyName(ExecState *exec) const
Performs the GetPropertyName type conversion operation on this value (ECMA 8.7)
Definition: reference.cpp:103
KJS::Reference::getBase
Value getBase(ExecState *exec) const
Performs the GetBase type conversion operation on this value (ECMA 8.7)
Definition: reference.cpp:92
KJS::Reference::putValue
void putValue(ExecState *exec, const Value &w)
Performs the PutValue type conversion operation on this value (ECMA 8.7.1)
Definition: reference.cpp:145
KJS::Reference::getValue
Value getValue(ExecState *exec) const
Performs the GetValue type conversion operation on this value (ECMA 8.7.1)
Definition: reference.cpp:117
KJS::ScopeChain
A scope chain object.
Definition: scope_chain.h:47
KJS::String
Represents an primitive String value.
Definition: value.h:340
KJS::UString
Unicode string class.
Definition: ustring.h:189
KJS::UString::ascii
char * ascii() const
Convert the Unicode string to plain ASCII chars chopping of any higher bytes.
Definition: ustring.cpp:485
KJS::UString::cstring
CString cstring() const
Definition: ustring.cpp:480
KJS::Undefined
Represents an primitive Undefined value.
Definition: value.h:269
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::toInt32
int toInt32(ExecState *exec) const
Performs the ToInt32 type conversion operation on this value (ECMA 9.5)
Definition: value.h:231
KJS::Value::toBoolean
bool toBoolean(ExecState *exec) const
Performs the ToBoolean type conversion operation on this value (ECMA 9.2)
Definition: value.h:216
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
endl
kndbgstream & endl(kndbgstream &s)
TDEStdAccel::next
const TDEShortcut & next()
TDEStdAccel::name
TQString name(StdAccel id)
TDEStdAccel::label
TQString label(StdAccel id)

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.