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

Last change on this file since 13304 was 13304, checked in by mjs, 19 years ago

Reviewed by Anders.


The memory usage of Node was reduced by 2 machine words per node:

  • sourceURL was removed and only kept on FunctionBodyNode. The source URL can only be distinct per function or top-level program node, and you always have one.


  • refcount was removed and kept in a separate hashtable when greater than 1. newNodes set represents floating nodes with refcount of 0. This helps because almost all nodes have a refcount of 1 for almost all of their lifetime.


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