source: webkit/trunk/JavaScriptCore/kjs/nodes.cpp@ 14902

Last change on this file since 14902 was 14893, checked in by andersca, 19 years ago

2006-06-17 Anders Carlsson <[email protected]>

Reviewed by Maciej and Geoff.

http://bugzilla.opendarwin.org/show_bug.cgi?id=7080
Provide some way to stop a JavaScript infinite loop


  • kjs/completion.h: (KJS::): Add Interrupted completion type.


  • kjs/function.cpp: (KJS::FunctionImp::callAsFunction): (KJS::GlobalFuncImp::callAsFunction): Only set the exception on the new ExecState if the current one has had one.


  • kjs/interpreter.cpp: (KJS::TimeoutChecker::startTimeoutCheck): (KJS::TimeoutChecker::stopTimeoutCheck): (KJS::TimeoutChecker::alarmHandler): (KJS::TimeoutChecker::pauseTimeoutCheck): (KJS::TimeoutChecker::resumeTimeoutCheck): New TimeoutChecker class which handles setting Interpreter::m_timedOut flag after a given period of time. This currently only works on Unix platforms where setitimer and signals are used.


(KJS::Interpreter::Interpreter):
Initialize new member variables.


(KJS::Interpreter::~Interpreter):
Destroy the timeout checker.


(KJS::Interpreter::startTimeoutCheck):
(KJS::Interpreter::stopTimeoutCheck):
(KJS::Interpreter::pauseTimeoutCheck):
(KJS::Interpreter::resumeTimeoutCheck):
Call the timeout checker.


(KJS::Interpreter::handleTimeout):
Called on timeout. Resets the m_timedOut flag and calls shouldInterruptScript.


  • kjs/interpreter.h: (KJS::Interpreter::setTimeoutTime): New function for setting the timeout time.


(KJS::Interpreter::shouldInterruptScript):
New function. The idea is that this should be overridden by subclasses in order to for example
pop up a dialog asking the user if the script should be interrupted.


(KJS::Interpreter::checkTimeout):
New function which checks the m_timedOut flag and calls handleTimeout if it's set.


  • kjs/nodes.cpp: (DoWhileNode::execute): (WhileNode::execute): (ForNode::execute): Call Interpreter::checkTimeout after each iteration of the loop.
  • Property allow-tabs set to x
  • Property svn:eol-style set to native
File size: 62.9 KB
Line 
1/*
2 * This file is part of the KDE libraries
3 * Copyright (C) 1999-2002 Harri Porten ([email protected])
4 * Copyright (C) 2001 Peter Kelly ([email protected])
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 "config.h"
25#include "nodes.h"
26
27#include <math.h>
28#ifdef KJS_DEBUG_MEM
29#include <stdio.h>
30#include <typeinfo>
31#endif
32
33#include "context.h"
34#include "debugger.h"
35#include "function_object.h"
36#include "lexer.h"
37#include "operations.h"
38#include "reference_list.h"
39#include <wtf/HashSet.h>
40#include <wtf/HashCountedSet.h>
41
42using namespace KJS;
43
44#define KJS_BREAKPOINT \
45 if (Debugger::debuggersPresent > 0 && !hitStatement(exec)) \
46 return Completion(Normal);
47
48#define KJS_ABORTPOINT \
49 if (Debugger::debuggersPresent > 0 && \
50 exec->dynamicInterpreter()->imp()->debugger() && \
51 exec->dynamicInterpreter()->imp()->debugger()->imp()->aborted()) \
52 return Completion(Normal);
53
54#define KJS_CHECKEXCEPTION \
55 if (exec->hadException()) { \
56 setExceptionDetailsIfNeeded(exec); \
57 JSValue *ex = exec->exception(); \
58 exec->clearException(); \
59 return Completion(Throw, ex); \
60 } \
61 if (Collector::isOutOfMemory()) \
62 return Completion(Throw, Error::create(exec, GeneralError, "Out of memory"));
63
64#define KJS_CHECKEXCEPTIONVALUE \
65 if (exec->hadException()) { \
66 setExceptionDetailsIfNeeded(exec); \
67 return jsUndefined(); \
68 } \
69 if (Collector::isOutOfMemory()) \
70 return jsUndefined(); // will be picked up by KJS_CHECKEXCEPTION
71
72#define KJS_CHECKEXCEPTIONLIST \
73 if (exec->hadException()) { \
74 setExceptionDetailsIfNeeded(exec); \
75 return List(); \
76 } \
77 if (Collector::isOutOfMemory()) \
78 return List(); // will be picked up by KJS_CHECKEXCEPTION
79
80// ------------------------------ Node -----------------------------------------
81
82
83#ifndef NDEBUG
84struct NodeCounter {
85 static int count;
86 ~NodeCounter() { if (count != 0) fprintf(stderr, "LEAK: %d KJS::Node\n", count); }
87};
88int NodeCounter::count = 0;
89static NodeCounter nodeImplCounter;
90#endif
91
92static HashSet<Node*>* newNodes;
93static HashCountedSet<Node*>* nodeExtraRefCounts;
94
95Node::Node()
96{
97#ifndef NDEBUG
98 ++NodeCounter::count;
99#endif
100 m_line = Lexer::curr()->lineNo();
101 if (!newNodes)
102 newNodes = new HashSet<Node*>;
103 newNodes->add(this);
104}
105
106Node::~Node()
107{
108#ifndef NDEBUG
109 --NodeCounter::count;
110#endif
111}
112
113void Node::ref()
114{
115 // bumping from 0 to 1 is just removing from the new nodes set
116 if (newNodes) {
117 HashSet<Node*>::iterator it = newNodes->find(this);
118 if (it != newNodes->end()) {
119 newNodes->remove(it);
120 ASSERT(!nodeExtraRefCounts || !nodeExtraRefCounts->contains(this));
121 return;
122 }
123 }
124
125 ASSERT(!newNodes || !newNodes->contains(this));
126
127 if (!nodeExtraRefCounts)
128 nodeExtraRefCounts = new HashCountedSet<Node*>;
129 nodeExtraRefCounts->add(this);
130}
131
132void Node::deref()
133{
134 ASSERT(!newNodes || !newNodes->contains(this));
135
136 if (!nodeExtraRefCounts) {
137 delete this;
138 return;
139 }
140
141 HashCountedSet<Node*>::iterator it = nodeExtraRefCounts->find(this);
142 if (it == nodeExtraRefCounts->end())
143 delete this;
144 else
145 nodeExtraRefCounts->remove(it);
146}
147
148unsigned Node::refcount()
149{
150 if (newNodes && newNodes->contains(this)) {
151 ASSERT(!nodeExtraRefCounts || !nodeExtraRefCounts->contains(this));
152 return 0;
153 }
154
155 ASSERT(!newNodes || !newNodes->contains(this));
156
157 if (!nodeExtraRefCounts)
158 return 1;
159
160 return 1 + nodeExtraRefCounts->count(this);
161}
162
163void Node::clearNewNodes()
164{
165 if (!newNodes)
166 return;
167
168#ifndef NDEBUG
169 HashSet<Node*>::iterator end = newNodes->end();
170 for (HashSet<Node*>::iterator it = newNodes->begin(); it != end; ++it)
171 ASSERT(!nodeExtraRefCounts || !nodeExtraRefCounts->contains(*it));
172#endif
173 deleteAllValues(*newNodes);
174 delete newNodes;
175 newNodes = 0;
176}
177
178static void substitute(UString &string, const UString &substring)
179{
180 int position = string.find("%s");
181 assert(position != -1);
182 string = string.substr(0, position) + substring + string.substr(position + 2);
183}
184
185static inline int currentSourceId(ExecState* exec)
186{
187 return exec->context()->currentBody()->sourceId();
188}
189
190static inline const UString& currentSourceURL(ExecState* exec)
191{
192 return exec->context()->currentBody()->sourceURL();
193}
194
195Completion Node::createErrorCompletion(ExecState* exec, ErrorType e, const char *msg)
196{
197 return Completion(Throw, Error::create(exec, e, msg, lineNo(), currentSourceId(exec), &currentSourceURL(exec)));
198}
199
200Completion Node::createErrorCompletion(ExecState *exec, ErrorType e, const char *msg, const Identifier &ident)
201{
202 UString message = msg;
203 substitute(message, ident.ustring());
204 return Completion(Throw, Error::create(exec, e, message, lineNo(), currentSourceId(exec), &currentSourceURL(exec)));
205}
206
207JSValue *Node::throwError(ExecState* exec, ErrorType e, const char *msg)
208{
209 return KJS::throwError(exec, e, msg, lineNo(), currentSourceId(exec), &currentSourceURL(exec));
210}
211
212JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, Node *expr)
213{
214 UString message = msg;
215 substitute(message, v->toString(exec));
216 substitute(message, expr->toString());
217 return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), &currentSourceURL(exec));
218}
219
220
221JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, const Identifier &label)
222{
223 UString message = msg;
224 substitute(message, label.ustring());
225 return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), &currentSourceURL(exec));
226}
227
228JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, Node *e1, Node *e2)
229{
230 UString message = msg;
231 substitute(message, v->toString(exec));
232 substitute(message, e1->toString());
233 substitute(message, e2->toString());
234 return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), &currentSourceURL(exec));
235}
236
237JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, Node *expr, const Identifier &label)
238{
239 UString message = msg;
240 substitute(message, v->toString(exec));
241 substitute(message, expr->toString());
242 substitute(message, label.ustring());
243 return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), &currentSourceURL(exec));
244}
245
246JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, const Identifier &label)
247{
248 UString message = msg;
249 substitute(message, v->toString(exec));
250 substitute(message, label.ustring());
251 return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), &currentSourceURL(exec));
252}
253
254JSValue *Node::throwUndefinedVariableError(ExecState *exec, const Identifier &ident)
255{
256 return throwError(exec, ReferenceError, "Can't find variable: %s", ident);
257}
258
259void Node::setExceptionDetailsIfNeeded(ExecState *exec)
260{
261 JSValue *exceptionValue = exec->exception();
262 if (exceptionValue->isObject()) {
263 JSObject *exception = static_cast<JSObject *>(exceptionValue);
264 if (!exception->hasProperty(exec, "line") && !exception->hasProperty(exec, "sourceURL")) {
265 exception->put(exec, "line", jsNumber(m_line));
266 exception->put(exec, "sourceURL", jsString(currentSourceURL(exec)));
267 }
268 }
269}
270
271Node *Node::nodeInsideAllParens()
272{
273 return this;
274}
275
276// ------------------------------ StatementNode --------------------------------
277
278StatementNode::StatementNode()
279 : m_lastLine(-1)
280{
281 m_line = -1;
282}
283
284void StatementNode::setLoc(int firstLine, int lastLine)
285{
286 m_line = firstLine;
287 m_lastLine = lastLine;
288}
289
290// return true if the debugger wants us to stop at this point
291bool StatementNode::hitStatement(ExecState* exec)
292{
293 Debugger *dbg = exec->dynamicInterpreter()->debugger();
294 if (dbg)
295 return dbg->atStatement(exec, currentSourceId(exec), firstLine(), lastLine());
296 else
297 return true; // continue
298}
299
300void StatementNode::processFuncDecl(ExecState*)
301{
302}
303
304// ------------------------------ NullNode -------------------------------------
305
306JSValue *NullNode::evaluate(ExecState *)
307{
308 return jsNull();
309}
310
311// ------------------------------ BooleanNode ----------------------------------
312
313JSValue *BooleanNode::evaluate(ExecState *)
314{
315 return jsBoolean(value);
316}
317
318// ------------------------------ NumberNode -----------------------------------
319
320JSValue *NumberNode::evaluate(ExecState *)
321{
322 return jsNumber(value);
323}
324
325// ------------------------------ StringNode -----------------------------------
326
327JSValue *StringNode::evaluate(ExecState *)
328{
329 return jsString(value);
330}
331
332// ------------------------------ RegExpNode -----------------------------------
333
334JSValue *RegExpNode::evaluate(ExecState *exec)
335{
336 List list;
337 list.append(jsString(pattern));
338 list.append(jsString(flags));
339
340 JSObject *reg = exec->lexicalInterpreter()->builtinRegExp();
341 return reg->construct(exec,list);
342}
343
344// ------------------------------ ThisNode -------------------------------------
345
346// ECMA 11.1.1
347JSValue *ThisNode::evaluate(ExecState *exec)
348{
349 return exec->context()->thisValue();
350}
351
352// ------------------------------ ResolveNode ----------------------------------
353
354// ECMA 11.1.2 & 10.1.4
355JSValue *ResolveNode::evaluate(ExecState *exec)
356{
357 const ScopeChain& chain = exec->context()->scopeChain();
358 ScopeChainIterator iter = chain.begin();
359 ScopeChainIterator end = chain.end();
360
361 // we must always have something in the scope chain
362 assert(iter != end);
363
364 PropertySlot slot;
365 do {
366 JSObject *o = *iter;
367
368 if (o->getPropertySlot(exec, ident, slot))
369 return slot.getValue(exec, o, ident);
370
371 ++iter;
372 } while (iter != end);
373
374 return throwUndefinedVariableError(exec, ident);
375}
376
377// ------------------------------ GroupNode ------------------------------------
378
379// ECMA 11.1.6
380JSValue *GroupNode::evaluate(ExecState *exec)
381{
382 return group->evaluate(exec);
383}
384
385Node *GroupNode::nodeInsideAllParens()
386{
387 Node *n = this;
388 do
389 n = static_cast<GroupNode *>(n)->group.get();
390 while (n->isGroupNode());
391 return n;
392}
393
394// ------------------------------ ElementNode ----------------------------------
395
396// ECMA 11.1.4
397JSValue *ElementNode::evaluate(ExecState *exec)
398{
399 JSObject *array = exec->lexicalInterpreter()->builtinArray()->construct(exec, List::empty());
400 int length = 0;
401 for (ElementNode *n = this; n; n = n->next.get()) {
402 JSValue *val = n->node->evaluate(exec);
403 KJS_CHECKEXCEPTIONVALUE
404 length += n->elision;
405 array->put(exec, length++, val);
406 }
407 return array;
408}
409
410void ElementNode::breakCycle()
411{
412 next = 0;
413}
414
415// ------------------------------ ArrayNode ------------------------------------
416
417// ECMA 11.1.4
418JSValue *ArrayNode::evaluate(ExecState *exec)
419{
420 JSObject *array;
421 int length;
422
423 if (element) {
424 array = static_cast<JSObject*>(element->evaluate(exec));
425 KJS_CHECKEXCEPTIONVALUE
426 length = opt ? array->get(exec,lengthPropertyName)->toInt32(exec) : 0;
427 } else {
428 JSValue *newArr = exec->lexicalInterpreter()->builtinArray()->construct(exec,List::empty());
429 array = static_cast<JSObject*>(newArr);
430 length = 0;
431 }
432
433 if (opt)
434 array->put(exec,lengthPropertyName, jsNumber(elision + length), DontEnum | DontDelete);
435
436 return array;
437}
438
439// ------------------------------ ObjectLiteralNode ----------------------------
440
441// ECMA 11.1.5
442JSValue *ObjectLiteralNode::evaluate(ExecState *exec)
443{
444 if (list)
445 return list->evaluate(exec);
446
447 return exec->lexicalInterpreter()->builtinObject()->construct(exec,List::empty());
448}
449
450// ------------------------------ PropertyListNode -----------------------------
451
452// ECMA 11.1.5
453JSValue *PropertyListNode::evaluate(ExecState *exec)
454{
455 JSObject *obj = exec->lexicalInterpreter()->builtinObject()->construct(exec, List::empty());
456
457 for (PropertyListNode *p = this; p; p = p->next.get()) {
458 JSValue *n = p->node->name->evaluate(exec);
459 KJS_CHECKEXCEPTIONVALUE
460 JSValue *v = p->node->assign->evaluate(exec);
461 KJS_CHECKEXCEPTIONVALUE
462
463 Identifier propertyName = Identifier(n->toString(exec));
464 switch (p->node->type) {
465 case PropertyNode::Getter:
466 assert(v->isObject());
467 obj->defineGetter(exec, propertyName, static_cast<JSObject *>(v));
468 break;
469 case PropertyNode::Setter:
470 assert(v->isObject());
471 obj->defineSetter(exec, propertyName, static_cast<JSObject *>(v));
472 break;
473 case PropertyNode::Constant:
474 obj->put(exec, propertyName, v);
475 break;
476 }
477 }
478
479 return obj;
480}
481
482void PropertyListNode::breakCycle()
483{
484 next = 0;
485}
486
487// ------------------------------ PropertyNode -----------------------------
488// ECMA 11.1.5
489JSValue *PropertyNode::evaluate(ExecState*)
490{
491 assert(false);
492 return jsNull();
493}
494
495// ---------------------------- PropertyNameNode -------------------------------
496
497// ECMA 11.1.5
498JSValue *PropertyNameNode::evaluate(ExecState*)
499{
500 JSValue *s;
501
502 if (str.isNull()) {
503 s = jsString(UString::from(numeric));
504 } else {
505 s = jsString(str.ustring());
506 }
507
508 return s;
509}
510
511// ------------------------------ BracketAccessorNode --------------------------------
512
513// ECMA 11.2.1a
514JSValue *BracketAccessorNode::evaluate(ExecState *exec)
515{
516 JSValue *v1 = expr1->evaluate(exec);
517 KJS_CHECKEXCEPTIONVALUE
518 JSValue *v2 = expr2->evaluate(exec);
519 KJS_CHECKEXCEPTIONVALUE
520 JSObject *o = v1->toObject(exec);
521 uint32_t i;
522 if (v2->getUInt32(i))
523 return o->get(exec, i);
524 return o->get(exec, Identifier(v2->toString(exec)));
525}
526
527// ------------------------------ DotAccessorNode --------------------------------
528
529// ECMA 11.2.1b
530JSValue *DotAccessorNode::evaluate(ExecState *exec)
531{
532 JSValue *v = expr->evaluate(exec);
533 KJS_CHECKEXCEPTIONVALUE
534 return v->toObject(exec)->get(exec, ident);
535
536}
537
538// ------------------------------ ArgumentListNode -----------------------------
539
540JSValue *ArgumentListNode::evaluate(ExecState *)
541{
542 assert(0);
543 return 0; // dummy, see evaluateList()
544}
545
546// ECMA 11.2.4
547List ArgumentListNode::evaluateList(ExecState *exec)
548{
549 List l;
550
551 for (ArgumentListNode *n = this; n; n = n->next.get()) {
552 JSValue *v = n->expr->evaluate(exec);
553 KJS_CHECKEXCEPTIONLIST
554 l.append(v);
555 }
556
557 return l;
558}
559
560void ArgumentListNode::breakCycle()
561{
562 next = 0;
563}
564
565// ------------------------------ ArgumentsNode --------------------------------
566
567JSValue *ArgumentsNode::evaluate(ExecState *)
568{
569 assert(0);
570 return 0; // dummy, see evaluateList()
571}
572
573// ------------------------------ NewExprNode ----------------------------------
574
575// ECMA 11.2.2
576
577JSValue *NewExprNode::evaluate(ExecState *exec)
578{
579 JSValue *v = expr->evaluate(exec);
580 KJS_CHECKEXCEPTIONVALUE
581
582 List argList;
583 if (args) {
584 argList = args->evaluateList(exec);
585 KJS_CHECKEXCEPTIONVALUE
586 }
587
588 if (!v->isObject()) {
589 return throwError(exec, TypeError, "Value %s (result of expression %s) is not an object. Cannot be used with new.", v, expr.get());
590 }
591
592 JSObject *constr = static_cast<JSObject*>(v);
593 if (!constr->implementsConstruct()) {
594 return throwError(exec, TypeError, "Value %s (result of expression %s) is not a constructor. Cannot be used with new.", v, expr.get());
595 }
596
597 return constr->construct(exec, argList);
598}
599
600// ECMA 11.2.3
601JSValue *FunctionCallValueNode::evaluate(ExecState *exec)
602{
603 JSValue *v = expr->evaluate(exec);
604 KJS_CHECKEXCEPTIONVALUE
605
606 if (!v->isObject()) {
607 return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, expr.get());
608 }
609
610 JSObject *func = static_cast<JSObject*>(v);
611
612 if (!func->implementsCall()) {
613 return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, expr.get());
614 }
615
616 List argList = args->evaluateList(exec);
617 KJS_CHECKEXCEPTIONVALUE
618
619 JSObject *thisObj = exec->dynamicInterpreter()->globalObject();
620
621 return func->call(exec, thisObj, argList);
622}
623
624// ECMA 11.2.3
625JSValue *FunctionCallResolveNode::evaluate(ExecState *exec)
626{
627 const ScopeChain& chain = exec->context()->scopeChain();
628 ScopeChainIterator iter = chain.begin();
629 ScopeChainIterator end = chain.end();
630
631 // we must always have something in the scope chain
632 assert(iter != end);
633
634 PropertySlot slot;
635 JSObject *base;
636 do {
637 base = *iter;
638 if (base->getPropertySlot(exec, ident, slot)) {
639 JSValue *v = slot.getValue(exec, base, ident);
640 KJS_CHECKEXCEPTIONVALUE
641
642 if (!v->isObject()) {
643 return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, ident);
644 }
645
646 JSObject *func = static_cast<JSObject*>(v);
647
648 if (!func->implementsCall()) {
649 return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, ident);
650 }
651
652 List argList = args->evaluateList(exec);
653 KJS_CHECKEXCEPTIONVALUE
654
655 JSObject *thisObj = base;
656 // ECMA 11.2.3 says that in this situation the this value should be null.
657 // However, section 10.2.3 says that in the case where the value provided
658 // by the caller is null, the global object should be used. It also says
659 // that the section does not apply to interal functions, but for simplicity
660 // of implementation we use the global object anyway here. This guarantees
661 // that in host objects you always get a valid object for this.
662 if (thisObj->isActivation())
663 thisObj = exec->dynamicInterpreter()->globalObject();
664
665 return func->call(exec, thisObj, argList);
666 }
667 ++iter;
668 } while (iter != end);
669
670 return throwUndefinedVariableError(exec, ident);
671}
672
673// ECMA 11.2.3
674JSValue *FunctionCallBracketNode::evaluate(ExecState *exec)
675{
676 JSValue *baseVal = base->evaluate(exec);
677 KJS_CHECKEXCEPTIONVALUE
678
679 JSValue *subscriptVal = subscript->evaluate(exec);
680
681 JSObject *baseObj = baseVal->toObject(exec);
682 uint32_t i;
683 PropertySlot slot;
684
685 JSValue *funcVal;
686 if (subscriptVal->getUInt32(i)) {
687 if (baseObj->getPropertySlot(exec, i, slot))
688 funcVal = slot.getValue(exec, baseObj, i);
689 else
690 funcVal = jsUndefined();
691 } else {
692 Identifier ident(subscriptVal->toString(exec));
693 if (baseObj->getPropertySlot(exec, ident, slot))
694 funcVal = baseObj->get(exec, ident);
695 else
696 funcVal = jsUndefined();
697 }
698
699 KJS_CHECKEXCEPTIONVALUE
700
701 if (!funcVal->isObject()) {
702 return throwError(exec, TypeError, "Value %s (result of expression %s[%s]) is not object.", funcVal, base.get(), subscript.get());
703 }
704
705 JSObject *func = static_cast<JSObject*>(funcVal);
706
707 if (!func->implementsCall()) {
708 return throwError(exec, TypeError, "Object %s (result of expression %s[%s]) does not allow calls.", funcVal, base.get(), subscript.get());
709 }
710
711 List argList = args->evaluateList(exec);
712 KJS_CHECKEXCEPTIONVALUE
713
714 JSObject *thisObj = baseObj;
715 assert(thisObj);
716 assert(thisObj->isObject());
717 assert(!thisObj->isActivation());
718
719 return func->call(exec, thisObj, argList);
720}
721
722static const char *dotExprNotAnObjectString()
723{
724 return "Value %s (result of expression %s.%s) is not object.";
725}
726
727static const char *dotExprDoesNotAllowCallsString()
728{
729 return "Object %s (result of expression %s.%s) does not allow calls.";
730}
731
732// ECMA 11.2.3
733JSValue *FunctionCallDotNode::evaluate(ExecState *exec)
734{
735 JSValue *baseVal = base->evaluate(exec);
736
737 JSObject *baseObj = baseVal->toObject(exec);
738 PropertySlot slot;
739 JSValue *funcVal = baseObj->getPropertySlot(exec, ident, slot) ? slot.getValue(exec, baseObj, ident) : jsUndefined();
740 KJS_CHECKEXCEPTIONVALUE
741
742 if (!funcVal->isObject())
743 return throwError(exec, TypeError, dotExprNotAnObjectString(), funcVal, base.get(), ident);
744
745 JSObject *func = static_cast<JSObject*>(funcVal);
746
747 if (!func->implementsCall())
748 return throwError(exec, TypeError, dotExprDoesNotAllowCallsString(), funcVal, base.get(), ident);
749
750 List argList = args->evaluateList(exec);
751 KJS_CHECKEXCEPTIONVALUE
752
753 JSObject *thisObj = baseObj;
754 assert(thisObj);
755 assert(thisObj->isObject());
756 assert(!thisObj->isActivation());
757
758 return func->call(exec, thisObj, argList);
759}
760
761// ECMA 11.3
762
763// ------------------------------ PostfixResolveNode ----------------------------------
764
765JSValue *PostfixResolveNode::evaluate(ExecState *exec)
766{
767 const ScopeChain& chain = exec->context()->scopeChain();
768 ScopeChainIterator iter = chain.begin();
769 ScopeChainIterator end = chain.end();
770
771 // we must always have something in the scope chain
772 assert(iter != end);
773
774 PropertySlot slot;
775 JSObject *base;
776 do {
777 base = *iter;
778 if (base->getPropertySlot(exec, m_ident, slot)) {
779 JSValue *v = slot.getValue(exec, base, m_ident);
780
781 double n = v->toNumber(exec);
782
783 double newValue = (m_oper == OpPlusPlus) ? n + 1 : n - 1;
784 base->put(exec, m_ident, jsNumber(newValue));
785
786 return jsNumber(n);
787 }
788
789 ++iter;
790 } while (iter != end);
791
792 return throwUndefinedVariableError(exec, m_ident);
793}
794
795// ------------------------------ PostfixBracketNode ----------------------------------
796
797JSValue *PostfixBracketNode::evaluate(ExecState *exec)
798{
799 JSValue *baseValue = m_base->evaluate(exec);
800 KJS_CHECKEXCEPTIONVALUE
801 JSValue *subscript = m_subscript->evaluate(exec);
802 KJS_CHECKEXCEPTIONVALUE
803
804 JSObject *base = baseValue->toObject(exec);
805
806 uint32_t propertyIndex;
807 if (subscript->getUInt32(propertyIndex)) {
808 PropertySlot slot;
809 JSValue *v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
810 KJS_CHECKEXCEPTIONVALUE
811
812 double n = v->toNumber(exec);
813
814 double newValue = (m_oper == OpPlusPlus) ? n + 1 : n - 1;
815 base->put(exec, propertyIndex, jsNumber(newValue));
816
817 return jsNumber(n);
818 }
819
820 Identifier propertyName(subscript->toString(exec));
821 PropertySlot slot;
822 JSValue *v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
823 KJS_CHECKEXCEPTIONVALUE
824
825 double n = v->toNumber(exec);
826
827 double newValue = (m_oper == OpPlusPlus) ? n + 1 : n - 1;
828 base->put(exec, propertyName, jsNumber(newValue));
829
830 return jsNumber(n);
831}
832
833// ------------------------------ PostfixDotNode ----------------------------------
834
835JSValue *PostfixDotNode::evaluate(ExecState *exec)
836{
837 JSValue *baseValue = m_base->evaluate(exec);
838 KJS_CHECKEXCEPTIONVALUE
839 JSObject *base = baseValue->toObject(exec);
840
841 PropertySlot slot;
842 JSValue *v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
843 KJS_CHECKEXCEPTIONVALUE
844
845 double n = v->toNumber(exec);
846
847 double newValue = (m_oper == OpPlusPlus) ? n + 1 : n - 1;
848 base->put(exec, m_ident, jsNumber(newValue));
849
850 return jsNumber(n);
851}
852
853// ECMA 11.4.1
854
855// ------------------------------ DeleteResolveNode -----------------------------------
856JSValue *DeleteResolveNode::evaluate(ExecState *exec)
857{
858 const ScopeChain& chain = exec->context()->scopeChain();
859 ScopeChainIterator iter = chain.begin();
860 ScopeChainIterator end = chain.end();
861
862 // we must always have something in the scope chain
863 assert(iter != end);
864
865 PropertySlot slot;
866 JSObject *base;
867 do {
868 base = *iter;
869 if (base->getPropertySlot(exec, m_ident, slot)) {
870 return jsBoolean(base->deleteProperty(exec, m_ident));
871 }
872
873 ++iter;
874 } while (iter != end);
875
876 return jsBoolean(true);
877}
878
879// ------------------------------ DeleteBracketNode -----------------------------------
880JSValue *DeleteBracketNode::evaluate(ExecState *exec)
881{
882 JSValue *baseValue = m_base->evaluate(exec);
883 KJS_CHECKEXCEPTIONVALUE
884 JSValue *subscript = m_subscript->evaluate(exec);
885 KJS_CHECKEXCEPTIONVALUE
886
887 JSObject *base = baseValue->toObject(exec);
888
889 uint32_t propertyIndex;
890 if (subscript->getUInt32(propertyIndex))
891 return jsBoolean(base->deleteProperty(exec, propertyIndex));
892
893 Identifier propertyName(subscript->toString(exec));
894 return jsBoolean(base->deleteProperty(exec, propertyName));
895}
896
897// ------------------------------ DeleteDotNode -----------------------------------
898JSValue *DeleteDotNode::evaluate(ExecState *exec)
899{
900 JSValue *baseValue = m_base->evaluate(exec);
901 JSObject *base = baseValue->toObject(exec);
902 KJS_CHECKEXCEPTIONVALUE
903
904 return jsBoolean(base->deleteProperty(exec, m_ident));
905}
906
907// ------------------------------ DeleteValueNode -----------------------------------
908JSValue *DeleteValueNode::evaluate(ExecState *exec)
909{
910 m_expr->evaluate(exec);
911 KJS_CHECKEXCEPTIONVALUE
912
913 // delete on a non-location expression ignores the value and returns true
914 return jsBoolean(true);
915}
916
917// ------------------------------ VoidNode -------------------------------------
918
919// ECMA 11.4.2
920JSValue *VoidNode::evaluate(ExecState *exec)
921{
922 expr->evaluate(exec);
923 KJS_CHECKEXCEPTIONVALUE
924
925 return jsUndefined();
926}
927
928// ECMA 11.4.3
929
930// ------------------------------ TypeOfValueNode -----------------------------------
931
932static JSValue *typeStringForValue(JSValue *v)
933{
934 switch (v->type()) {
935 case UndefinedType:
936 return jsString("undefined");
937 case NullType:
938 return jsString("object");
939 case BooleanType:
940 return jsString("boolean");
941 case NumberType:
942 return jsString("number");
943 case StringType:
944 return jsString("string");
945 default:
946 if (v->isObject()) {
947 // Return "undefined" for objects that should be treated
948 // as null when doing comparisons.
949 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
950 return jsString("undefined");
951 else if (static_cast<JSObject*>(v)->implementsCall())
952 return jsString("function");
953 }
954
955 return jsString("object");
956 }
957}
958
959JSValue *TypeOfResolveNode::evaluate(ExecState *exec)
960{
961 const ScopeChain& chain = exec->context()->scopeChain();
962 ScopeChainIterator iter = chain.begin();
963 ScopeChainIterator end = chain.end();
964
965 // we must always have something in the scope chain
966 assert(iter != end);
967
968 PropertySlot slot;
969 JSObject *base;
970 do {
971 base = *iter;
972 if (base->getPropertySlot(exec, m_ident, slot)) {
973 JSValue *v = slot.getValue(exec, base, m_ident);
974 return typeStringForValue(v);
975 }
976
977 ++iter;
978 } while (iter != end);
979
980 return jsString("undefined");
981}
982
983// ------------------------------ TypeOfValueNode -----------------------------------
984
985JSValue *TypeOfValueNode::evaluate(ExecState *exec)
986{
987 JSValue *v = m_expr->evaluate(exec);
988 KJS_CHECKEXCEPTIONVALUE
989
990 return typeStringForValue(v);
991}
992
993// ECMA 11.4.4 and 11.4.5
994
995// ------------------------------ PrefixResolveNode ----------------------------------
996
997JSValue *PrefixResolveNode::evaluate(ExecState *exec)
998{
999 const ScopeChain& chain = exec->context()->scopeChain();
1000 ScopeChainIterator iter = chain.begin();
1001 ScopeChainIterator end = chain.end();
1002
1003 // we must always have something in the scope chain
1004 assert(iter != end);
1005
1006 PropertySlot slot;
1007 JSObject *base;
1008 do {
1009 base = *iter;
1010 if (base->getPropertySlot(exec, m_ident, slot)) {
1011 JSValue *v = slot.getValue(exec, base, m_ident);
1012
1013 double n = v->toNumber(exec);
1014
1015 double newValue = (m_oper == OpPlusPlus) ? n + 1 : n - 1;
1016 JSValue *n2 = jsNumber(newValue);
1017 base->put(exec, m_ident, n2);
1018
1019 return n2;
1020 }
1021
1022 ++iter;
1023 } while (iter != end);
1024
1025 return throwUndefinedVariableError(exec, m_ident);
1026}
1027
1028// ------------------------------ PrefixBracketNode ----------------------------------
1029
1030JSValue *PrefixBracketNode::evaluate(ExecState *exec)
1031{
1032 JSValue *baseValue = m_base->evaluate(exec);
1033 KJS_CHECKEXCEPTIONVALUE
1034 JSValue *subscript = m_subscript->evaluate(exec);
1035 KJS_CHECKEXCEPTIONVALUE
1036
1037 JSObject *base = baseValue->toObject(exec);
1038
1039 uint32_t propertyIndex;
1040 if (subscript->getUInt32(propertyIndex)) {
1041 PropertySlot slot;
1042 JSValue *v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
1043 KJS_CHECKEXCEPTIONVALUE
1044
1045 double n = v->toNumber(exec);
1046
1047 double newValue = (m_oper == OpPlusPlus) ? n + 1 : n - 1;
1048 JSValue *n2 = jsNumber(newValue);
1049 base->put(exec, propertyIndex, n2);
1050
1051 return n2;
1052 }
1053
1054 Identifier propertyName(subscript->toString(exec));
1055 PropertySlot slot;
1056 JSValue *v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
1057 KJS_CHECKEXCEPTIONVALUE
1058
1059 double n = v->toNumber(exec);
1060
1061 double newValue = (m_oper == OpPlusPlus) ? n + 1 : n - 1;
1062 JSValue *n2 = jsNumber(newValue);
1063 base->put(exec, propertyName, n2);
1064
1065 return n2;
1066}
1067
1068// ------------------------------ PrefixDotNode ----------------------------------
1069
1070JSValue *PrefixDotNode::evaluate(ExecState *exec)
1071{
1072 JSValue *baseValue = m_base->evaluate(exec);
1073 KJS_CHECKEXCEPTIONVALUE
1074 JSObject *base = baseValue->toObject(exec);
1075
1076 PropertySlot slot;
1077 JSValue *v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
1078 KJS_CHECKEXCEPTIONVALUE
1079
1080 double n = v->toNumber(exec);
1081
1082 double newValue = (m_oper == OpPlusPlus) ? n + 1 : n - 1;
1083 JSValue *n2 = jsNumber(newValue);
1084 base->put(exec, m_ident, n2);
1085
1086 return n2;
1087}
1088
1089// ------------------------------ UnaryPlusNode --------------------------------
1090
1091// ECMA 11.4.6
1092JSValue *UnaryPlusNode::evaluate(ExecState *exec)
1093{
1094 JSValue *v = expr->evaluate(exec);
1095 KJS_CHECKEXCEPTIONVALUE
1096
1097 return jsNumber(v->toNumber(exec));
1098}
1099
1100// ------------------------------ NegateNode -----------------------------------
1101
1102// ECMA 11.4.7
1103JSValue *NegateNode::evaluate(ExecState *exec)
1104{
1105 JSValue *v = expr->evaluate(exec);
1106 KJS_CHECKEXCEPTIONVALUE
1107
1108 double n = v->toNumber(exec);
1109 return jsNumber(-n);
1110}
1111
1112// ------------------------------ BitwiseNotNode -------------------------------
1113
1114// ECMA 11.4.8
1115JSValue *BitwiseNotNode::evaluate(ExecState *exec)
1116{
1117 JSValue *v = expr->evaluate(exec);
1118 KJS_CHECKEXCEPTIONVALUE
1119 return jsNumber(~v->toInt32(exec));
1120}
1121
1122// ------------------------------ LogicalNotNode -------------------------------
1123
1124// ECMA 11.4.9
1125JSValue *LogicalNotNode::evaluate(ExecState *exec)
1126{
1127 JSValue *v = expr->evaluate(exec);
1128 KJS_CHECKEXCEPTIONVALUE
1129 return jsBoolean(!v->toBoolean(exec));
1130}
1131
1132// ------------------------------ MultNode -------------------------------------
1133
1134// ECMA 11.5
1135JSValue *MultNode::evaluate(ExecState *exec)
1136{
1137 JSValue *v1 = term1->evaluate(exec);
1138 KJS_CHECKEXCEPTIONVALUE
1139
1140 JSValue *v2 = term2->evaluate(exec);
1141 KJS_CHECKEXCEPTIONVALUE
1142
1143 return mult(exec, v1, v2, oper);
1144}
1145
1146// ------------------------------ AddNode --------------------------------------
1147
1148// ECMA 11.6
1149JSValue *AddNode::evaluate(ExecState *exec)
1150{
1151 JSValue *v1 = term1->evaluate(exec);
1152 KJS_CHECKEXCEPTIONVALUE
1153
1154 JSValue *v2 = term2->evaluate(exec);
1155 KJS_CHECKEXCEPTIONVALUE
1156
1157 return add(exec, v1, v2, oper);
1158}
1159
1160// ------------------------------ ShiftNode ------------------------------------
1161
1162// ECMA 11.7
1163JSValue *ShiftNode::evaluate(ExecState *exec)
1164{
1165 JSValue *v1 = term1->evaluate(exec);
1166 KJS_CHECKEXCEPTIONVALUE
1167 JSValue *v2 = term2->evaluate(exec);
1168 KJS_CHECKEXCEPTIONVALUE
1169 unsigned int i2 = v2->toUInt32(exec);
1170 i2 &= 0x1f;
1171
1172 switch (oper) {
1173 case OpLShift:
1174 return jsNumber(v1->toInt32(exec) << i2);
1175 case OpRShift:
1176 return jsNumber(v1->toInt32(exec) >> i2);
1177 case OpURShift:
1178 return jsNumber(v1->toUInt32(exec) >> i2);
1179 default:
1180 assert(!"ShiftNode: unhandled switch case");
1181 return jsUndefined();
1182 }
1183}
1184
1185// ------------------------------ RelationalNode -------------------------------
1186
1187// ECMA 11.8
1188JSValue *RelationalNode::evaluate(ExecState *exec)
1189{
1190 JSValue *v1 = expr1->evaluate(exec);
1191 KJS_CHECKEXCEPTIONVALUE
1192 JSValue *v2 = expr2->evaluate(exec);
1193 KJS_CHECKEXCEPTIONVALUE
1194
1195 bool b;
1196 if (oper == OpLess || oper == OpGreaterEq) {
1197 int r = relation(exec, v1, v2);
1198 if (r < 0)
1199 b = false;
1200 else
1201 b = (oper == OpLess) ? (r == 1) : (r == 0);
1202 } else if (oper == OpGreater || oper == OpLessEq) {
1203 int r = relation(exec, v2, v1);
1204 if (r < 0)
1205 b = false;
1206 else
1207 b = (oper == OpGreater) ? (r == 1) : (r == 0);
1208 } else if (oper == OpIn) {
1209 // Is all of this OK for host objects?
1210 if (!v2->isObject())
1211 return throwError(exec, TypeError,
1212 "Value %s (result of expression %s) is not an object. Cannot be used with IN expression.", v2, expr2.get());
1213 JSObject *o2(static_cast<JSObject*>(v2));
1214 b = o2->hasProperty(exec, Identifier(v1->toString(exec)));
1215 } else {
1216 if (!v2->isObject())
1217 return throwError(exec, TypeError,
1218 "Value %s (result of expression %s) is not an object. Cannot be used with instanceof operator.", v2, expr2.get());
1219
1220 JSObject *o2(static_cast<JSObject*>(v2));
1221 if (!o2->implementsHasInstance()) {
1222 // According to the spec, only some types of objects "implement" the [[HasInstance]] property.
1223 // But we are supposed to throw an exception where the object does not "have" the [[HasInstance]]
1224 // property. It seems that all object have the property, but not all implement it, so in this
1225 // case we return false (consistent with mozilla)
1226 return jsBoolean(false);
1227 // return throwError(exec, TypeError,
1228 // "Object does not implement the [[HasInstance]] method." );
1229 }
1230 return jsBoolean(o2->hasInstance(exec, v1));
1231 }
1232
1233 return jsBoolean(b);
1234}
1235
1236// ------------------------------ EqualNode ------------------------------------
1237
1238// ECMA 11.9
1239JSValue *EqualNode::evaluate(ExecState *exec)
1240{
1241 JSValue *v1 = expr1->evaluate(exec);
1242 KJS_CHECKEXCEPTIONVALUE
1243 JSValue *v2 = expr2->evaluate(exec);
1244 KJS_CHECKEXCEPTIONVALUE
1245
1246 bool result;
1247 if (oper == OpEqEq || oper == OpNotEq) {
1248 // == and !=
1249 bool eq = equal(exec,v1, v2);
1250 result = oper == OpEqEq ? eq : !eq;
1251 } else {
1252 // === and !==
1253 bool eq = strictEqual(exec,v1, v2);
1254 result = oper == OpStrEq ? eq : !eq;
1255 }
1256 return jsBoolean(result);
1257}
1258
1259// ------------------------------ BitOperNode ----------------------------------
1260
1261// ECMA 11.10
1262JSValue *BitOperNode::evaluate(ExecState *exec)
1263{
1264 JSValue *v1 = expr1->evaluate(exec);
1265 KJS_CHECKEXCEPTIONVALUE
1266 JSValue *v2 = expr2->evaluate(exec);
1267 KJS_CHECKEXCEPTIONVALUE
1268 int i1 = v1->toInt32(exec);
1269 int i2 = v2->toInt32(exec);
1270 int result;
1271 if (oper == OpBitAnd)
1272 result = i1 & i2;
1273 else if (oper == OpBitXOr)
1274 result = i1 ^ i2;
1275 else
1276 result = i1 | i2;
1277
1278 return jsNumber(result);
1279}
1280
1281// ------------------------------ BinaryLogicalNode ----------------------------
1282
1283// ECMA 11.11
1284JSValue *BinaryLogicalNode::evaluate(ExecState *exec)
1285{
1286 JSValue *v1 = expr1->evaluate(exec);
1287 KJS_CHECKEXCEPTIONVALUE
1288 bool b1 = v1->toBoolean(exec);
1289 if ((!b1 && oper == OpAnd) || (b1 && oper == OpOr))
1290 return v1;
1291
1292 JSValue *v2 = expr2->evaluate(exec);
1293 KJS_CHECKEXCEPTIONVALUE
1294
1295 return v2;
1296}
1297
1298// ------------------------------ ConditionalNode ------------------------------
1299
1300// ECMA 11.12
1301JSValue *ConditionalNode::evaluate(ExecState *exec)
1302{
1303 JSValue *v = logical->evaluate(exec);
1304 KJS_CHECKEXCEPTIONVALUE
1305 bool b = v->toBoolean(exec);
1306
1307 if (b)
1308 v = expr1->evaluate(exec);
1309 else
1310 v = expr2->evaluate(exec);
1311 KJS_CHECKEXCEPTIONVALUE
1312
1313 return v;
1314}
1315
1316// ECMA 11.13
1317
1318static ALWAYS_INLINE JSValue *valueForReadModifyAssignment(ExecState * exec, JSValue *v1, JSValue *v2, Operator oper)
1319{
1320 JSValue *v;
1321 int i1;
1322 int i2;
1323 unsigned int ui;
1324 switch (oper) {
1325 case OpMultEq:
1326 v = mult(exec, v1, v2, '*');
1327 break;
1328 case OpDivEq:
1329 v = mult(exec, v1, v2, '/');
1330 break;
1331 case OpPlusEq:
1332 v = add(exec, v1, v2, '+');
1333 break;
1334 case OpMinusEq:
1335 v = add(exec, v1, v2, '-');
1336 break;
1337 case OpLShift:
1338 i1 = v1->toInt32(exec);
1339 i2 = v2->toInt32(exec);
1340 v = jsNumber(i1 << i2);
1341 break;
1342 case OpRShift:
1343 i1 = v1->toInt32(exec);
1344 i2 = v2->toInt32(exec);
1345 v = jsNumber(i1 >> i2);
1346 break;
1347 case OpURShift:
1348 ui = v1->toUInt32(exec);
1349 i2 = v2->toInt32(exec);
1350 v = jsNumber(ui >> i2);
1351 break;
1352 case OpAndEq:
1353 i1 = v1->toInt32(exec);
1354 i2 = v2->toInt32(exec);
1355 v = jsNumber(i1 & i2);
1356 break;
1357 case OpXOrEq:
1358 i1 = v1->toInt32(exec);
1359 i2 = v2->toInt32(exec);
1360 v = jsNumber(i1 ^ i2);
1361 break;
1362 case OpOrEq:
1363 i1 = v1->toInt32(exec);
1364 i2 = v2->toInt32(exec);
1365 v = jsNumber(i1 | i2);
1366 break;
1367 case OpModEq: {
1368 double d1 = v1->toNumber(exec);
1369 double d2 = v2->toNumber(exec);
1370 v = jsNumber(fmod(d1, d2));
1371 }
1372 break;
1373 default:
1374 assert(0);
1375 v = jsUndefined();
1376 }
1377
1378 return v;
1379}
1380
1381// ------------------------------ AssignResolveNode -----------------------------------
1382
1383JSValue *AssignResolveNode::evaluate(ExecState *exec)
1384{
1385 const ScopeChain& chain = exec->context()->scopeChain();
1386 ScopeChainIterator iter = chain.begin();
1387 ScopeChainIterator end = chain.end();
1388
1389 // we must always have something in the scope chain
1390 assert(iter != end);
1391
1392 PropertySlot slot;
1393 JSObject *base;
1394 do {
1395 base = *iter;
1396 if (base->getPropertySlot(exec, m_ident, slot))
1397 goto found;
1398
1399 ++iter;
1400 } while (iter != end);
1401
1402 if (m_oper != OpEqual)
1403 return throwUndefinedVariableError(exec, m_ident);
1404
1405 found:
1406 JSValue *v;
1407
1408 if (m_oper == OpEqual) {
1409 v = m_right->evaluate(exec);
1410 } else {
1411 JSValue *v1 = slot.getValue(exec, base, m_ident);
1412 KJS_CHECKEXCEPTIONVALUE
1413 JSValue *v2 = m_right->evaluate(exec);
1414 v = valueForReadModifyAssignment(exec, v1, v2, m_oper);
1415 }
1416
1417 KJS_CHECKEXCEPTIONVALUE
1418
1419 base->put(exec, m_ident, v);
1420 return v;
1421}
1422
1423// ------------------------------ AssignDotNode -----------------------------------
1424
1425JSValue *AssignDotNode::evaluate(ExecState *exec)
1426{
1427 JSValue *baseValue = m_base->evaluate(exec);
1428 KJS_CHECKEXCEPTIONVALUE
1429 JSObject *base = baseValue->toObject(exec);
1430
1431 JSValue *v;
1432
1433 if (m_oper == OpEqual) {
1434 v = m_right->evaluate(exec);
1435 } else {
1436 PropertySlot slot;
1437 JSValue *v1 = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
1438 KJS_CHECKEXCEPTIONVALUE
1439 JSValue *v2 = m_right->evaluate(exec);
1440 v = valueForReadModifyAssignment(exec, v1, v2, m_oper);
1441 }
1442
1443 KJS_CHECKEXCEPTIONVALUE
1444
1445 base->put(exec, m_ident, v);
1446 return v;
1447}
1448
1449// ------------------------------ AssignBracketNode -----------------------------------
1450
1451JSValue *AssignBracketNode::evaluate(ExecState *exec)
1452{
1453 JSValue *baseValue = m_base->evaluate(exec);
1454 KJS_CHECKEXCEPTIONVALUE
1455 JSValue *subscript = m_subscript->evaluate(exec);
1456 KJS_CHECKEXCEPTIONVALUE
1457
1458 JSObject *base = baseValue->toObject(exec);
1459
1460 uint32_t propertyIndex;
1461 if (subscript->getUInt32(propertyIndex)) {
1462 JSValue *v;
1463 if (m_oper == OpEqual) {
1464 v = m_right->evaluate(exec);
1465 } else {
1466 PropertySlot slot;
1467 JSValue *v1 = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
1468 KJS_CHECKEXCEPTIONVALUE
1469 JSValue *v2 = m_right->evaluate(exec);
1470 v = valueForReadModifyAssignment(exec, v1, v2, m_oper);
1471 }
1472
1473 KJS_CHECKEXCEPTIONVALUE
1474
1475 base->put(exec, propertyIndex, v);
1476 return v;
1477 }
1478
1479 Identifier propertyName(subscript->toString(exec));
1480 JSValue *v;
1481
1482 if (m_oper == OpEqual) {
1483 v = m_right->evaluate(exec);
1484 } else {
1485 PropertySlot slot;
1486 JSValue *v1 = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
1487 KJS_CHECKEXCEPTIONVALUE
1488 JSValue *v2 = m_right->evaluate(exec);
1489 v = valueForReadModifyAssignment(exec, v1, v2, m_oper);
1490 }
1491
1492 KJS_CHECKEXCEPTIONVALUE
1493
1494 base->put(exec, propertyName, v);
1495 return v;
1496}
1497
1498// ------------------------------ CommaNode ------------------------------------
1499
1500// ECMA 11.14
1501JSValue *CommaNode::evaluate(ExecState *exec)
1502{
1503 expr1->evaluate(exec);
1504 KJS_CHECKEXCEPTIONVALUE
1505 JSValue *v = expr2->evaluate(exec);
1506 KJS_CHECKEXCEPTIONVALUE
1507
1508 return v;
1509}
1510
1511// ------------------------------ AssignExprNode -------------------------------
1512
1513// ECMA 12.2
1514JSValue *AssignExprNode::evaluate(ExecState *exec)
1515{
1516 return expr->evaluate(exec);
1517}
1518
1519// ------------------------------ VarDeclNode ----------------------------------
1520
1521
1522VarDeclNode::VarDeclNode(const Identifier &id, AssignExprNode *in, Type t)
1523 : varType(t), ident(id), init(in)
1524{
1525}
1526
1527// ECMA 12.2
1528JSValue *VarDeclNode::evaluate(ExecState *exec)
1529{
1530 JSObject* variable = exec->context()->variableObject();
1531
1532 JSValue* val;
1533 if (init) {
1534 val = init->evaluate(exec);
1535 KJS_CHECKEXCEPTIONVALUE
1536 } else {
1537 // already declared? - check with getDirect so you can override
1538 // built-in properties of the global object with var declarations.
1539 if (variable->getDirect(ident))
1540 return 0;
1541 val = jsUndefined();
1542 }
1543
1544#ifdef KJS_VERBOSE
1545 printInfo(exec,(UString("new variable ")+ident.ustring()).cstring().c_str(),val);
1546#endif
1547 // We use Internal to bypass all checks in derived objects, e.g. so that
1548 // "var location" creates a dynamic property instead of activating window.location.
1549 int flags = Internal;
1550 if (exec->context()->codeType() != EvalCode)
1551 flags |= DontDelete;
1552 if (varType == VarDeclNode::Constant)
1553 flags |= ReadOnly;
1554 variable->put(exec, ident, val, flags);
1555
1556 return jsString(ident.ustring());
1557}
1558
1559void VarDeclNode::processVarDecls(ExecState *exec)
1560{
1561 JSObject* variable = exec->context()->variableObject();
1562
1563 // If a variable by this name already exists, don't clobber it -
1564 // it might be a function parameter
1565 if (!variable->hasProperty(exec, ident)) {
1566 int flags = Internal;
1567 if (exec->context()->codeType() != EvalCode)
1568 flags |= DontDelete;
1569 if (varType == VarDeclNode::Constant)
1570 flags |= ReadOnly;
1571 variable->put(exec, ident, jsUndefined(), flags);
1572 }
1573}
1574
1575// ------------------------------ VarDeclListNode ------------------------------
1576
1577// ECMA 12.2
1578JSValue *VarDeclListNode::evaluate(ExecState *exec)
1579{
1580 for (VarDeclListNode *n = this; n; n = n->next.get()) {
1581 n->var->evaluate(exec);
1582 KJS_CHECKEXCEPTIONVALUE
1583 }
1584 return jsUndefined();
1585}
1586
1587void VarDeclListNode::processVarDecls(ExecState *exec)
1588{
1589 for (VarDeclListNode *n = this; n; n = n->next.get())
1590 n->var->processVarDecls(exec);
1591}
1592
1593void VarDeclListNode::breakCycle()
1594{
1595 next = 0;
1596}
1597
1598// ------------------------------ VarStatementNode -----------------------------
1599
1600// ECMA 12.2
1601Completion VarStatementNode::execute(ExecState *exec)
1602{
1603 KJS_BREAKPOINT;
1604
1605 (void) next->evaluate(exec);
1606 KJS_CHECKEXCEPTION
1607
1608 return Completion(Normal);
1609}
1610
1611void VarStatementNode::processVarDecls(ExecState *exec)
1612{
1613 next->processVarDecls(exec);
1614}
1615
1616// ------------------------------ BlockNode ------------------------------------
1617
1618BlockNode::BlockNode(SourceElementsNode *s)
1619{
1620 if (s) {
1621 source = s->next.release();
1622 Parser::removeNodeCycle(source.get());
1623 setLoc(s->firstLine(), s->lastLine());
1624 } else {
1625 source = 0;
1626 }
1627}
1628
1629// ECMA 12.1
1630Completion BlockNode::execute(ExecState *exec)
1631{
1632 if (!source)
1633 return Completion(Normal);
1634
1635 source->processFuncDecl(exec);
1636
1637 return source->execute(exec);
1638}
1639
1640void BlockNode::processVarDecls(ExecState *exec)
1641{
1642 if (source)
1643 source->processVarDecls(exec);
1644}
1645
1646// ------------------------------ EmptyStatementNode ---------------------------
1647
1648// ECMA 12.3
1649Completion EmptyStatementNode::execute(ExecState *)
1650{
1651 return Completion(Normal);
1652}
1653
1654// ------------------------------ ExprStatementNode ----------------------------
1655
1656// ECMA 12.4
1657Completion ExprStatementNode::execute(ExecState *exec)
1658{
1659 KJS_BREAKPOINT;
1660
1661 JSValue *v = expr->evaluate(exec);
1662 KJS_CHECKEXCEPTION
1663
1664 return Completion(Normal, v);
1665}
1666
1667// ------------------------------ IfNode ---------------------------------------
1668
1669// ECMA 12.5
1670Completion IfNode::execute(ExecState *exec)
1671{
1672 KJS_BREAKPOINT;
1673
1674 JSValue *v = expr->evaluate(exec);
1675 KJS_CHECKEXCEPTION
1676 bool b = v->toBoolean(exec);
1677
1678 // if ... then
1679 if (b)
1680 return statement1->execute(exec);
1681
1682 // no else
1683 if (!statement2)
1684 return Completion(Normal);
1685
1686 // else
1687 return statement2->execute(exec);
1688}
1689
1690void IfNode::processVarDecls(ExecState *exec)
1691{
1692 statement1->processVarDecls(exec);
1693
1694 if (statement2)
1695 statement2->processVarDecls(exec);
1696}
1697
1698// ------------------------------ DoWhileNode ----------------------------------
1699
1700// ECMA 12.6.1
1701Completion DoWhileNode::execute(ExecState *exec)
1702{
1703 KJS_BREAKPOINT;
1704
1705 JSValue *bv;
1706 Completion c;
1707
1708 do {
1709 // bail out on error
1710 KJS_CHECKEXCEPTION
1711
1712 exec->context()->pushIteration();
1713 c = statement->execute(exec);
1714 exec->context()->popIteration();
1715
1716 if (exec->dynamicInterpreter()->checkTimeout())
1717 return Completion(Interrupted);
1718
1719 if (!((c.complType() == Continue) && ls.contains(c.target()))) {
1720 if ((c.complType() == Break) && ls.contains(c.target()))
1721 return Completion(Normal, 0);
1722 if (c.complType() != Normal)
1723 return c;
1724 }
1725 bv = expr->evaluate(exec);
1726 KJS_CHECKEXCEPTION
1727 } while (bv->toBoolean(exec));
1728
1729 return Completion(Normal, 0);
1730}
1731
1732void DoWhileNode::processVarDecls(ExecState *exec)
1733{
1734 statement->processVarDecls(exec);
1735}
1736
1737// ------------------------------ WhileNode ------------------------------------
1738
1739// ECMA 12.6.2
1740Completion WhileNode::execute(ExecState *exec)
1741{
1742 KJS_BREAKPOINT;
1743
1744 JSValue *bv;
1745 Completion c;
1746 bool b(false);
1747 JSValue *value = 0;
1748
1749 while (1) {
1750 bv = expr->evaluate(exec);
1751 KJS_CHECKEXCEPTION
1752 b = bv->toBoolean(exec);
1753
1754 // bail out on error
1755 KJS_CHECKEXCEPTION
1756
1757 if (!b)
1758 return Completion(Normal, value);
1759
1760 exec->context()->pushIteration();
1761 c = statement->execute(exec);
1762 exec->context()->popIteration();
1763
1764 if (exec->dynamicInterpreter()->checkTimeout())
1765 return Completion(Interrupted);
1766
1767 if (c.isValueCompletion())
1768 value = c.value();
1769
1770 if ((c.complType() == Continue) && ls.contains(c.target()))
1771 continue;
1772 if ((c.complType() == Break) && ls.contains(c.target()))
1773 return Completion(Normal, value);
1774 if (c.complType() != Normal)
1775 return c;
1776 }
1777
1778 return Completion(); // work around gcc 4.0 bug
1779}
1780
1781void WhileNode::processVarDecls(ExecState *exec)
1782{
1783 statement->processVarDecls(exec);
1784}
1785
1786// ------------------------------ ForNode --------------------------------------
1787
1788// ECMA 12.6.3
1789Completion ForNode::execute(ExecState *exec)
1790{
1791 JSValue *v, *cval = 0;
1792
1793 if (expr1) {
1794 v = expr1->evaluate(exec);
1795 KJS_CHECKEXCEPTION
1796 }
1797 while (1) {
1798 if (expr2) {
1799 v = expr2->evaluate(exec);
1800 KJS_CHECKEXCEPTION
1801 if (!v->toBoolean(exec))
1802 return Completion(Normal, cval);
1803 }
1804 // bail out on error
1805 KJS_CHECKEXCEPTION
1806
1807 exec->context()->pushIteration();
1808 Completion c = statement->execute(exec);
1809 exec->context()->popIteration();
1810 if (c.isValueCompletion())
1811 cval = c.value();
1812 if (!((c.complType() == Continue) && ls.contains(c.target()))) {
1813 if ((c.complType() == Break) && ls.contains(c.target()))
1814 return Completion(Normal, cval);
1815 if (c.complType() != Normal)
1816 return c;
1817 }
1818
1819 if (exec->dynamicInterpreter()->checkTimeout())
1820 return Completion(Interrupted);
1821
1822 if (expr3) {
1823 v = expr3->evaluate(exec);
1824 KJS_CHECKEXCEPTION
1825 }
1826 }
1827
1828 return Completion(); // work around gcc 4.0 bug
1829}
1830
1831void ForNode::processVarDecls(ExecState *exec)
1832{
1833 if (expr1)
1834 expr1->processVarDecls(exec);
1835
1836 statement->processVarDecls(exec);
1837}
1838
1839// ------------------------------ ForInNode ------------------------------------
1840
1841ForInNode::ForInNode(Node *l, Node *e, StatementNode *s)
1842 : init(0L), lexpr(l), expr(e), varDecl(0L), statement(s)
1843{
1844}
1845
1846ForInNode::ForInNode(const Identifier &i, AssignExprNode *in, Node *e, StatementNode *s)
1847 : ident(i), init(in), expr(e), statement(s)
1848{
1849 // for( var foo = bar in baz )
1850 varDecl = new VarDeclNode(ident, init.get(), VarDeclNode::Variable);
1851 lexpr = new ResolveNode(ident);
1852}
1853
1854// ECMA 12.6.4
1855Completion ForInNode::execute(ExecState *exec)
1856{
1857 JSValue *e;
1858 JSValue *retval = 0;
1859 JSObject *v;
1860 Completion c;
1861 ReferenceList propList;
1862
1863 if (varDecl) {
1864 varDecl->evaluate(exec);
1865 KJS_CHECKEXCEPTION
1866 }
1867
1868 e = expr->evaluate(exec);
1869
1870 // for Null and Undefined, we want to make sure not to go through
1871 // the loop at all, because their object wrappers will have a
1872 // property list but will throw an exception if you attempt to
1873 // access any property.
1874 if (e->isUndefinedOrNull()) {
1875 return Completion(Normal, 0);
1876 }
1877
1878 KJS_CHECKEXCEPTION
1879 v = e->toObject(exec);
1880 propList = v->propList(exec);
1881
1882 ReferenceListIterator propIt = propList.begin();
1883
1884 while (propIt != propList.end()) {
1885 Identifier name = propIt->getPropertyName(exec);
1886 if (!v->hasProperty(exec, name)) {
1887 propIt++;
1888 continue;
1889 }
1890
1891 JSValue *str = jsString(name.ustring());
1892
1893 if (lexpr->isResolveNode()) {
1894 const Identifier &ident = static_cast<ResolveNode *>(lexpr.get())->identifier();
1895
1896 const ScopeChain& chain = exec->context()->scopeChain();
1897 ScopeChainIterator iter = chain.begin();
1898 ScopeChainIterator end = chain.end();
1899
1900 // we must always have something in the scope chain
1901 assert(iter != end);
1902
1903 PropertySlot slot;
1904 JSObject *o;
1905 do {
1906 o = *iter;
1907 if (o->getPropertySlot(exec, ident, slot)) {
1908 o->put(exec, ident, str);
1909 break;
1910 }
1911 ++iter;
1912 } while (iter != end);
1913
1914 if (iter == end)
1915 o->put(exec, ident, str);
1916 } else if (lexpr->isDotAccessorNode()) {
1917 const Identifier& ident = static_cast<DotAccessorNode *>(lexpr.get())->identifier();
1918 JSValue *v = static_cast<DotAccessorNode *>(lexpr.get())->base()->evaluate(exec);
1919 KJS_CHECKEXCEPTION
1920 JSObject *o = v->toObject(exec);
1921
1922 o->put(exec, ident, str);
1923 } else {
1924 assert(lexpr->isBracketAccessorNode());
1925 JSValue *v = static_cast<BracketAccessorNode *>(lexpr.get())->base()->evaluate(exec);
1926 KJS_CHECKEXCEPTION
1927 JSValue *v2 = static_cast<BracketAccessorNode *>(lexpr.get())->subscript()->evaluate(exec);
1928 KJS_CHECKEXCEPTION
1929 JSObject *o = v->toObject(exec);
1930
1931 uint32_t i;
1932 if (v2->getUInt32(i))
1933 o->put(exec, i, str);
1934 o->put(exec, Identifier(v2->toString(exec)), str);
1935 }
1936
1937 KJS_CHECKEXCEPTION
1938
1939 exec->context()->pushIteration();
1940 c = statement->execute(exec);
1941 exec->context()->popIteration();
1942 if (c.isValueCompletion())
1943 retval = c.value();
1944
1945 if (!((c.complType() == Continue) && ls.contains(c.target()))) {
1946 if ((c.complType() == Break) && ls.contains(c.target()))
1947 break;
1948 if (c.complType() != Normal) {
1949 return c;
1950 }
1951 }
1952
1953 propIt++;
1954 }
1955
1956 // bail out on error
1957 KJS_CHECKEXCEPTION
1958
1959 return Completion(Normal, retval);
1960}
1961
1962void ForInNode::processVarDecls(ExecState *exec)
1963{
1964 if (varDecl)
1965 varDecl->processVarDecls(exec);
1966 statement->processVarDecls(exec);
1967}
1968
1969// ------------------------------ ContinueNode ---------------------------------
1970
1971// ECMA 12.7
1972Completion ContinueNode::execute(ExecState *exec)
1973{
1974 KJS_BREAKPOINT;
1975
1976 if (ident.isEmpty() && !exec->context()->inIteration())
1977 return createErrorCompletion(exec, SyntaxError, "Invalid continue statement.");
1978 else if (!ident.isEmpty() && !exec->context()->seenLabels()->contains(ident))
1979 return createErrorCompletion(exec, SyntaxError, "Label %s not found.", ident);
1980 else
1981 return Completion(Continue, 0, ident);
1982}
1983
1984// ------------------------------ BreakNode ------------------------------------
1985
1986// ECMA 12.8
1987Completion BreakNode::execute(ExecState *exec)
1988{
1989 KJS_BREAKPOINT;
1990
1991 if (ident.isEmpty() && !exec->context()->inIteration() &&
1992 !exec->context()->inSwitch())
1993 return createErrorCompletion(exec, SyntaxError, "Invalid break statement.");
1994 else if (!ident.isEmpty() && !exec->context()->seenLabels()->contains(ident))
1995 return createErrorCompletion(exec, SyntaxError, "Label %s not found.");
1996 else
1997 return Completion(Break, 0, ident);
1998}
1999
2000// ------------------------------ ReturnNode -----------------------------------
2001
2002// ECMA 12.9
2003Completion ReturnNode::execute(ExecState *exec)
2004{
2005 KJS_BREAKPOINT;
2006
2007 CodeType codeType = exec->context()->codeType();
2008 if (codeType != FunctionCode && codeType != AnonymousCode ) {
2009 return createErrorCompletion(exec, SyntaxError, "Invalid return statement.");
2010 }
2011
2012 if (!value)
2013 return Completion(ReturnValue, jsUndefined());
2014
2015 JSValue *v = value->evaluate(exec);
2016 KJS_CHECKEXCEPTION
2017
2018 return Completion(ReturnValue, v);
2019}
2020
2021// ------------------------------ WithNode -------------------------------------
2022
2023// ECMA 12.10
2024Completion WithNode::execute(ExecState *exec)
2025{
2026 KJS_BREAKPOINT;
2027
2028 JSValue *v = expr->evaluate(exec);
2029 KJS_CHECKEXCEPTION
2030 JSObject *o = v->toObject(exec);
2031 KJS_CHECKEXCEPTION
2032 exec->context()->pushScope(o);
2033 Completion res = statement->execute(exec);
2034 exec->context()->popScope();
2035
2036 return res;
2037}
2038
2039void WithNode::processVarDecls(ExecState *exec)
2040{
2041 statement->processVarDecls(exec);
2042}
2043
2044// ------------------------------ CaseClauseNode -------------------------------
2045
2046// ECMA 12.11
2047JSValue *CaseClauseNode::evaluate(ExecState *exec)
2048{
2049 JSValue *v = expr->evaluate(exec);
2050 KJS_CHECKEXCEPTIONVALUE
2051
2052 return v;
2053}
2054
2055// ECMA 12.11
2056Completion CaseClauseNode::evalStatements(ExecState *exec)
2057{
2058 if (source)
2059 return source->execute(exec);
2060 else
2061 return Completion(Normal, jsUndefined());
2062}
2063
2064void CaseClauseNode::processVarDecls(ExecState *exec)
2065{
2066 if (source)
2067 source->processVarDecls(exec);
2068}
2069
2070void CaseClauseNode::processFuncDecl(ExecState* exec)
2071{
2072 if (source)
2073 source->processFuncDecl(exec);
2074}
2075
2076// ------------------------------ ClauseListNode -------------------------------
2077
2078JSValue *ClauseListNode::evaluate(ExecState *)
2079{
2080 // should never be called
2081 assert(false);
2082 return 0;
2083}
2084
2085// ECMA 12.11
2086void ClauseListNode::processVarDecls(ExecState *exec)
2087{
2088 for (ClauseListNode *n = this; n; n = n->next.get())
2089 if (n->clause)
2090 n->clause->processVarDecls(exec);
2091}
2092
2093void ClauseListNode::processFuncDecl(ExecState* exec)
2094{
2095 for (ClauseListNode* n = this; n; n = n->next.get())
2096 if (n->clause)
2097 n->clause->processFuncDecl(exec);
2098}
2099
2100void ClauseListNode::breakCycle()
2101{
2102 next = 0;
2103}
2104
2105// ------------------------------ CaseBlockNode --------------------------------
2106
2107CaseBlockNode::CaseBlockNode(ClauseListNode *l1, CaseClauseNode *d,
2108 ClauseListNode *l2)
2109{
2110 if (l1) {
2111 list1 = l1->next.release();
2112 Parser::removeNodeCycle(list1.get());
2113 } else {
2114 list1 = 0;
2115 }
2116
2117 def = d;
2118
2119 if (l2) {
2120 list2 = l2->next.release();
2121 Parser::removeNodeCycle(list2.get());
2122 } else {
2123 list2 = 0;
2124 }
2125}
2126
2127JSValue *CaseBlockNode::evaluate(ExecState *)
2128{
2129 // should never be called
2130 assert(false);
2131 return 0;
2132}
2133
2134// ECMA 12.11
2135Completion CaseBlockNode::evalBlock(ExecState *exec, JSValue *input)
2136{
2137 JSValue *v;
2138 Completion res;
2139 ClauseListNode *a = list1.get();
2140 ClauseListNode *b = list2.get();
2141 CaseClauseNode *clause;
2142
2143 while (a) {
2144 clause = a->getClause();
2145 a = a->getNext();
2146 v = clause->evaluate(exec);
2147 KJS_CHECKEXCEPTION
2148 if (strictEqual(exec, input, v)) {
2149 res = clause->evalStatements(exec);
2150 if (res.complType() != Normal)
2151 return res;
2152 while (a) {
2153 res = a->getClause()->evalStatements(exec);
2154 if (res.complType() != Normal)
2155 return res;
2156 a = a->getNext();
2157 }
2158 break;
2159 }
2160 }
2161
2162 while (b) {
2163 clause = b->getClause();
2164 b = b->getNext();
2165 v = clause->evaluate(exec);
2166 KJS_CHECKEXCEPTION
2167 if (strictEqual(exec, input, v)) {
2168 res = clause->evalStatements(exec);
2169 if (res.complType() != Normal)
2170 return res;
2171 goto step18;
2172 }
2173 }
2174
2175 // default clause
2176 if (def) {
2177 res = def->evalStatements(exec);
2178 if (res.complType() != Normal)
2179 return res;
2180 }
2181 b = list2.get();
2182 step18:
2183 while (b) {
2184 clause = b->getClause();
2185 res = clause->evalStatements(exec);
2186 if (res.complType() != Normal)
2187 return res;
2188 b = b->getNext();
2189 }
2190
2191 // bail out on error
2192 KJS_CHECKEXCEPTION
2193
2194 return Completion(Normal);
2195}
2196
2197void CaseBlockNode::processVarDecls(ExecState *exec)
2198{
2199 if (list1)
2200 list1->processVarDecls(exec);
2201 if (def)
2202 def->processVarDecls(exec);
2203 if (list2)
2204 list2->processVarDecls(exec);
2205}
2206
2207void CaseBlockNode::processFuncDecl(ExecState* exec)
2208{
2209 if (list1)
2210 list1->processFuncDecl(exec);
2211 if (def)
2212 def->processFuncDecl(exec);
2213 if (list2)
2214 list2->processFuncDecl(exec);
2215}
2216
2217// ------------------------------ SwitchNode -----------------------------------
2218
2219// ECMA 12.11
2220Completion SwitchNode::execute(ExecState *exec)
2221{
2222 KJS_BREAKPOINT;
2223
2224 JSValue *v = expr->evaluate(exec);
2225 KJS_CHECKEXCEPTION
2226
2227 exec->context()->pushSwitch();
2228 Completion res = block->evalBlock(exec,v);
2229 exec->context()->popSwitch();
2230
2231 if ((res.complType() == Break) && ls.contains(res.target()))
2232 return Completion(Normal, res.value());
2233 return res;
2234}
2235
2236void SwitchNode::processVarDecls(ExecState *exec)
2237{
2238 block->processVarDecls(exec);
2239}
2240
2241void SwitchNode::processFuncDecl(ExecState* exec)
2242{
2243 block->processFuncDecl(exec);
2244}
2245
2246// ------------------------------ LabelNode ------------------------------------
2247
2248// ECMA 12.12
2249Completion LabelNode::execute(ExecState *exec)
2250{
2251 if (!exec->context()->seenLabels()->push(label))
2252 return createErrorCompletion(exec, SyntaxError, "Duplicated label %s found.", label);
2253 Completion e = statement->execute(exec);
2254 exec->context()->seenLabels()->pop();
2255
2256 if ((e.complType() == Break) && (e.target() == label))
2257 return Completion(Normal, e.value());
2258 return e;
2259}
2260
2261void LabelNode::processVarDecls(ExecState *exec)
2262{
2263 statement->processVarDecls(exec);
2264}
2265
2266// ------------------------------ ThrowNode ------------------------------------
2267
2268// ECMA 12.13
2269Completion ThrowNode::execute(ExecState *exec)
2270{
2271 KJS_BREAKPOINT;
2272
2273 JSValue *v = expr->evaluate(exec);
2274 KJS_CHECKEXCEPTION
2275
2276 return Completion(Throw, v);
2277}
2278
2279// ------------------------------ TryNode --------------------------------------
2280
2281// ECMA 12.14
2282Completion TryNode::execute(ExecState *exec)
2283{
2284 KJS_BREAKPOINT;
2285
2286 Completion c = tryBlock->execute(exec);
2287
2288 if (catchBlock && c.complType() == Throw) {
2289 JSObject *obj = new JSObject;
2290 obj->put(exec, exceptionIdent, c.value(), DontDelete);
2291 exec->context()->pushScope(obj);
2292 c = catchBlock->execute(exec);
2293 exec->context()->popScope();
2294 }
2295
2296 if (finallyBlock) {
2297 Completion c2 = finallyBlock->execute(exec);
2298 if (c2.complType() != Normal)
2299 c = c2;
2300 }
2301
2302 return c;
2303}
2304
2305void TryNode::processVarDecls(ExecState *exec)
2306{
2307 tryBlock->processVarDecls(exec);
2308 if (catchBlock)
2309 catchBlock->processVarDecls(exec);
2310 if (finallyBlock)
2311 finallyBlock->processVarDecls(exec);
2312}
2313
2314// ------------------------------ ParameterNode --------------------------------
2315
2316// ECMA 13
2317JSValue *ParameterNode::evaluate(ExecState *)
2318{
2319 return jsUndefined();
2320}
2321
2322void ParameterNode::breakCycle()
2323{
2324 next = 0;
2325}
2326
2327// ------------------------------ FunctionBodyNode -----------------------------
2328
2329FunctionBodyNode::FunctionBodyNode(SourceElementsNode *s)
2330 : BlockNode(s)
2331 , m_sourceURL(Lexer::curr()->sourceURL())
2332 , m_sourceId(Parser::sid)
2333{
2334
2335 setLoc(-1, -1);
2336}
2337
2338void FunctionBodyNode::processFuncDecl(ExecState *exec)
2339{
2340 if (source)
2341 source->processFuncDecl(exec);
2342}
2343
2344// ------------------------------ FuncDeclNode ---------------------------------
2345
2346// ECMA 13
2347void FuncDeclNode::processFuncDecl(ExecState *exec)
2348{
2349 Context *context = exec->context();
2350
2351 // TODO: let this be an object with [[Class]] property "Function"
2352 FunctionImp *func = new DeclaredFunctionImp(exec, ident, body.get(), context->scopeChain());
2353
2354 JSObject *proto = exec->lexicalInterpreter()->builtinObject()->construct(exec, List::empty());
2355 proto->put(exec, constructorPropertyName, func, ReadOnly|DontDelete|DontEnum);
2356 func->put(exec, prototypePropertyName, proto, Internal|DontDelete);
2357
2358 int plen = 0;
2359 for(ParameterNode *p = param.get(); p != 0L; p = p->nextParam(), plen++)
2360 func->addParameter(p->ident());
2361
2362 func->put(exec, lengthPropertyName, jsNumber(plen), ReadOnly|DontDelete|DontEnum);
2363
2364 // ECMA 10.2.2
2365 context->variableObject()->put(exec, ident, func, Internal | (context->codeType() == EvalCode ? 0 : DontDelete));
2366
2367 if (body) {
2368 // hack the scope so that the function gets put as a property of func, and it's scope
2369 // contains the func as well as our current scope
2370 JSObject *oldVar = context->variableObject();
2371 context->setVariableObject(func);
2372 context->pushScope(func);
2373 body->processFuncDecl(exec);
2374 context->popScope();
2375 context->setVariableObject(oldVar);
2376 }
2377}
2378
2379Completion FuncDeclNode::execute(ExecState *)
2380{
2381 return Completion(Normal);
2382}
2383
2384// ------------------------------ FuncExprNode ---------------------------------
2385
2386// ECMA 13
2387JSValue *FuncExprNode::evaluate(ExecState *exec)
2388{
2389 Context *context = exec->context();
2390 bool named = !ident.isNull();
2391 JSObject *functionScopeObject = 0;
2392
2393 if (named) {
2394 // named FunctionExpressions can recursively call themselves,
2395 // but they won't register with the current scope chain and should
2396 // be contained as single property in an anonymous object.
2397 functionScopeObject = new JSObject;
2398 context->pushScope(functionScopeObject);
2399 }
2400
2401 FunctionImp *func = new DeclaredFunctionImp(exec, ident, body.get(), context->scopeChain());
2402 JSObject *proto = exec->lexicalInterpreter()->builtinObject()->construct(exec, List::empty());
2403 proto->put(exec, constructorPropertyName, func, ReadOnly|DontDelete|DontEnum);
2404 func->put(exec, prototypePropertyName, proto, Internal|DontDelete);
2405
2406 int plen = 0;
2407 for(ParameterNode *p = param.get(); p != 0L; p = p->nextParam(), plen++)
2408 func->addParameter(p->ident());
2409
2410 if (named) {
2411 functionScopeObject->put(exec, ident, func, Internal | ReadOnly | (context->codeType() == EvalCode ? 0 : DontDelete));
2412 context->popScope();
2413 }
2414
2415 return func;
2416}
2417
2418// ------------------------------ SourceElementsNode ---------------------------
2419
2420int SourceElementsNode::count = 0;
2421
2422SourceElementsNode::SourceElementsNode(StatementNode *s1)
2423 : node(s1), next(this)
2424{
2425 Parser::noteNodeCycle(this);
2426 setLoc(s1->firstLine(), s1->lastLine());
2427}
2428
2429SourceElementsNode::SourceElementsNode(SourceElementsNode *s1, StatementNode *s2)
2430 : node(s2), next(s1->next)
2431{
2432 s1->next = this;
2433 setLoc(s1->firstLine(), s2->lastLine());
2434}
2435
2436// ECMA 14
2437Completion SourceElementsNode::execute(ExecState *exec)
2438{
2439 KJS_CHECKEXCEPTION
2440
2441 Completion c1 = node->execute(exec);
2442 KJS_CHECKEXCEPTION;
2443 if (c1.complType() != Normal)
2444 return c1;
2445
2446 for (SourceElementsNode *n = next.get(); n; n = n->next.get()) {
2447 Completion c2 = n->node->execute(exec);
2448 if (c2.complType() != Normal)
2449 return c2;
2450 // The spec says to return c2 here, but it seems that mozilla returns c1 if
2451 // c2 doesn't have a value
2452 if (c2.value())
2453 c1 = c2;
2454 }
2455
2456 return c1;
2457}
2458
2459// ECMA 14
2460void SourceElementsNode::processFuncDecl(ExecState *exec)
2461{
2462 for (SourceElementsNode *n = this; n; n = n->next.get())
2463 n->node->processFuncDecl(exec);
2464}
2465
2466void SourceElementsNode::processVarDecls(ExecState *exec)
2467{
2468 for (SourceElementsNode *n = this; n; n = n->next.get())
2469 n->node->processVarDecls(exec);
2470}
2471
2472void SourceElementsNode::breakCycle()
2473{
2474 next = 0;
2475}
2476
2477ProgramNode::ProgramNode(SourceElementsNode *s) : FunctionBodyNode(s)
2478{
2479}
Note: See TracBrowser for help on using the repository browser.