source: webkit/trunk/JavaScriptCore/kjs/function.cpp@ 11375

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

JavaScriptCore:

Rubber stamped by Eric.

  • renamed SharedPtr to RefPtr via script
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • kjs/function.cpp: (KJS::GlobalFuncImp::callAsFunction):
  • kjs/function.h:
  • kjs/function_object.cpp: (FunctionObjectImp::construct):
  • kjs/internal.cpp: (KJS::Parser::parse): (KJS::InterpreterImp::checkSyntax): (KJS::InterpreterImp::evaluate):
  • kjs/internal.h:
  • kjs/nodes.h:
  • kjs/nodes2string.cpp: (KJS::SourceStream::operator<<):
  • kjs/protect.h:
  • kxmlcore/RefPtr.h: Added. (KXMLCore::RefPtr::RefPtr): (KXMLCore::RefPtr::~RefPtr): (KXMLCore::RefPtr::isNull): (KXMLCore::RefPtr::notNull): (KXMLCore::RefPtr::reset): (KXMLCore::RefPtr::get): (KXMLCore::RefPtr::operator*): (KXMLCore::RefPtr::operator->): (KXMLCore::RefPtr::operator!): (KXMLCore::RefPtr::operator UnspecifiedBoolType): (KXMLCore::::operator): (KXMLCore::operator==): (KXMLCore::operator!=): (KXMLCore::static_pointer_cast): (KXMLCore::const_pointer_cast):
  • kxmlcore/SharedPtr.h: Removed.

WebCore:

Rubber stamped by Eric.

  • renamed SharedPtr to RefPtr via script
  • ForwardingHeaders/kxmlcore/RefPtr.h: Added.
  • ForwardingHeaders/kxmlcore/SharedPtr.h: Removed.
  • khtml/css/css_computedstyle.h:
  • khtml/ecma/XSLTProcessor.cpp: (KJS::XSLTProcessorProtoFunc::callAsFunction):
  • khtml/ecma/XSLTProcessor.h:
  • khtml/ecma/domparser.h:
  • khtml/ecma/kjs_css.h:
  • khtml/ecma/kjs_dom.cpp: (KJS::DOMNamedNodesCollection::DOMNamedNodesCollection): (KJS::DOMNamedNodesCollection::getOwnPropertySlot):
  • khtml/ecma/kjs_dom.h:
  • khtml/ecma/kjs_events.h:
  • khtml/ecma/kjs_html.cpp: (KJS::HTMLDocument::namedItemGetter): (KJS::KJS::HTMLCollection::getNamedItems): (KJS::OptionConstructorImp::construct):
  • khtml/ecma/kjs_html.h:
  • khtml/ecma/kjs_range.h:
  • khtml/ecma/kjs_traversal.h:
  • khtml/ecma/kjs_views.h:
  • khtml/ecma/kjs_window.cpp: (KJS::Window::namedItemGetter):
  • khtml/ecma/xmlhttprequest.h:
  • khtml/editing/SelectionController.cpp: (khtml::SelectionController::toRange):
  • khtml/editing/SelectionController.h:
  • khtml/editing/apply_style_command.cpp: (khtml::StyleChange::init): (khtml::StyleChange::currentlyHasStyle): (khtml::ApplyStyleCommand::doApply): (khtml::ApplyStyleCommand::applyRelativeFontStyleChange): (khtml::ApplyStyleCommand::removeCSSStyle): (khtml::hasTextDecorationProperty): (khtml::ApplyStyleCommand::extractTextDecorationStyle): (khtml::ApplyStyleCommand::extractAndNegateTextDecorationStyle): (khtml::ApplyStyleCommand::pushDownTextDecorationStyleAroundNode): (khtml::ApplyStyleCommand::removeInlineStyle): (khtml::ApplyStyleCommand::addInlineStyleIfNeeded): (khtml::ApplyStyleCommand::computedFontSize):
  • khtml/editing/apply_style_command.h:
  • khtml/editing/edit_command.cpp: (khtml::EditCommandPtr::EditCommandPtr): (khtml::EditCommandPtr::operator=):
  • khtml/editing/edit_command.h:
  • khtml/editing/markup.cpp: (khtml::startMarkup):
  • khtml/editing/visible_position.cpp: (khtml::makeRange):
  • khtml/editing/visible_position.h:
  • khtml/editing/visible_range.h:
  • khtml/editing/visible_text.cpp: (khtml::TextIterator::range): (khtml::SimplifiedBackwardsTextIterator::range): (khtml::CharacterIterator::range): (khtml::TextIterator::rangeFromLocationAndLength): (khtml::findPlainText):
  • khtml/editing/visible_text.h: (khtml::WordAwareIterator::range):
  • khtml/editing/visible_units.cpp: (khtml::previousBoundary): (khtml::nextBoundary):
  • khtml/html/html_elementimpl.cpp: (HTMLElementImpl::children):
  • khtml/html/html_elementimpl.h:
  • khtml/html/html_formimpl.cpp: (DOM::HTMLFormElementImpl::elements): (DOM::HTMLSelectElementImpl::add): (DOM::HTMLSelectElementImpl::optionsHTMLCollection):
  • khtml/html/html_formimpl.h:
  • khtml/html/html_imageimpl.cpp: (DOM::HTMLMapElementImpl::areas):
  • khtml/html/html_imageimpl.h:
  • khtml/html/html_miscimpl.cpp: (DOM::HTMLCollectionImpl::namedItems):
  • khtml/html/html_miscimpl.h:
  • khtml/html/html_tableimpl.cpp: (DOM::HTMLTableElementImpl::rows): (DOM::HTMLTableElementImpl::tBodies): (DOM::HTMLTableSectionElementImpl::insertRow): (DOM::HTMLTableSectionElementImpl::deleteRow): (DOM::HTMLTableSectionElementImpl::rows): (DOM::HTMLTableRowElementImpl::insertCell): (DOM::HTMLTableRowElementImpl::deleteCell): (DOM::HTMLTableRowElementImpl::cells):
  • khtml/html/html_tableimpl.h:
  • khtml/html/htmlparser.cpp: (HTMLParser::parseToken): (HTMLParser::insertNode):
  • khtml/khtml_events.h:
  • khtml/khtml_part.cpp: (KHTMLPart::selectionHasStyle): (KHTMLPart::selectionStartHasStyle): (KHTMLPart::selectionComputedStyle): (KHTMLPart::applyEditingStyleToBodyElement): (KHTMLPart::removeEditingStyleFromBodyElement):
  • khtml/khtmlpart_p.h:
  • khtml/khtmlview.cpp: (KHTMLView::viewportMousePressEvent): (KHTMLView::viewportMouseDoubleClickEvent): (KHTMLView::viewportMouseReleaseEvent): (KHTMLView::dispatchMouseEvent):
  • khtml/misc/shared.h:
  • khtml/rendering/bidi.cpp:
  • khtml/rendering/render_block.cpp: (khtml::RenderBlock::updateFirstLetter):
  • khtml/rendering/render_line.h:
  • khtml/rendering/render_text.cpp: (RenderText::setStyle): (RenderText::originalString): (RenderTextFragment::originalString):
  • khtml/rendering/render_text.h:
  • khtml/xml/dom2_eventsimpl.h:
  • khtml/xml/dom2_rangeimpl.cpp: (DOM::rangeOfContents):
  • khtml/xml/dom2_rangeimpl.h:
  • khtml/xml/dom_docimpl.cpp: (DocumentImpl::adoptNode): (DocumentImpl::setFocusNode): (DocumentImpl::addMarker): (DocumentImpl::removeMarkers): (DocumentImpl::applyXSLTransform): (DocumentImpl::images): (DocumentImpl::applets): (DocumentImpl::embeds): (DocumentImpl::objects): (DocumentImpl::links): (DocumentImpl::forms): (DocumentImpl::anchors): (DocumentImpl::all): (DocumentImpl::windowNamedItems): (DocumentImpl::documentNamedItems): (DocumentImpl::getElementsByName):
  • khtml/xml/dom_docimpl.h: (DOM::DocumentImpl::transformSourceDocument):
  • khtml/xml/dom_elementimpl.cpp: (ElementImpl::setAttributeNode): (ElementImpl::removeAttributeNode): (NamedAttrMapImpl::removeNamedItemNS): (NamedAttrMapImpl::setNamedItem): (NamedAttrMapImpl::removeNamedItem):
  • khtml/xml/dom_elementimpl.h: (DOM::ElementImpl::setAttributeNodeNS):
  • khtml/xml/dom_nodeimpl.cpp: (DOM::NodeImpl::childNodes): (DOM::NodeImpl::dispatchWindowEvent): (DOM::NodeImpl::dispatchMouseEvent): (DOM::NodeImpl::getElementsByTagNameNS): (DOM::ContainerNodeImpl::insertBefore): (DOM::ContainerNodeImpl::replaceChild): (DOM::ContainerNodeImpl::appendChild): (DOM::ContainerNodeImpl::addChild):
  • khtml/xml/dom_nodeimpl.h: (DOM::NodeImpl::getElementsByTagName): (DOM::NamedNodeMapImpl::removeNamedItem): (DOM::NamedNodeMapImpl::setNamedItemNS):
  • khtml/xml/dom_xmlimpl.h:
  • khtml/xsl/xslt_processorimpl.cpp: (DOM::XSLTProcessorImpl::createDocumentFromSource): (DOM::createFragmentFromSource): (DOM::xsltStylesheetPointer): (DOM::xmlDocPtrFromNode): (DOM::XSLTProcessorImpl::transformToString): (DOM::XSLTProcessorImpl::transformToDocument): (DOM::XSLTProcessorImpl::transformToFragment): (DOM::XSLTProcessorImpl::getParameter):
  • khtml/xsl/xslt_processorimpl.h:
  • kwq/KWQClipboard.h:
  • kwq/KWQKHTMLPart.h:
  • kwq/KWQKHTMLPart.mm: (KWQKHTMLPart::findString): (KWQKHTMLPart::advanceToNextMisspelling): (KWQKHTMLPart::fontForSelection): (KWQKHTMLPart::markMisspellings): (KWQKHTMLPart::shouldClose):
  • kwq/WebCoreBridge.mm: (-[WebCoreBridge convertToNSRange:DOM::]):
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.8 KB
Line 
1// -*- c-basic-offset: 2 -*-
2/*
3 * This file is part of the KDE libraries
4 * Copyright (C) 1999-2002 Harri Porten ([email protected])
5 * Copyright (C) 2001 Peter Kelly ([email protected])
6 * Copyright (C) 2003 Apple Computer, Inc.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25#include "config.h"
26#include "function.h"
27
28#include "internal.h"
29#include "function_object.h"
30#include "lexer.h"
31#include "nodes.h"
32#include "operations.h"
33#include "debugger.h"
34#include "context.h"
35
36#include <stdio.h>
37#include <errno.h>
38#include <stdlib.h>
39#include <assert.h>
40#include <string.h>
41#include <ctype.h>
42
43#include <unicode/uchar.h>
44
45namespace KJS {
46
47// ----------------------------- FunctionImp ----------------------------------
48
49const ClassInfo FunctionImp::info = {"Function", &InternalFunctionImp::info, 0, 0};
50
51 class Parameter {
52 public:
53 Parameter(const Identifier &n) : name(n), next(0L) { }
54 ~Parameter() { delete next; }
55 Identifier name;
56 Parameter *next;
57 };
58
59FunctionImp::FunctionImp(ExecState *exec, const Identifier &n)
60 : InternalFunctionImp(
61 static_cast<FunctionPrototypeImp*>(exec->lexicalInterpreter()->builtinFunctionPrototype())
62 ), param(0L), ident(n)
63{
64}
65
66FunctionImp::~FunctionImp()
67{
68 delete param;
69}
70
71bool FunctionImp::implementsCall() const
72{
73 return true;
74}
75
76ValueImp *FunctionImp::callAsFunction(ExecState *exec, ObjectImp *thisObj, const List &args)
77{
78 ObjectImp *globalObj = exec->dynamicInterpreter()->globalObject();
79
80 // enter a new execution context
81 ContextImp ctx(globalObj, exec->dynamicInterpreter()->imp(), thisObj, codeType(),
82 exec->context().imp(), this, &args);
83 ExecState newExec(exec->dynamicInterpreter(), &ctx);
84 newExec.setException(exec->exception()); // could be null
85
86 // assign user supplied arguments to parameters
87 processParameters(&newExec, args);
88 // add variable declarations (initialized to undefined)
89 processVarDecls(&newExec);
90
91 Debugger *dbg = exec->dynamicInterpreter()->imp()->debugger();
92 int sid = -1;
93 int lineno = -1;
94 if (dbg) {
95 if (inherits(&DeclaredFunctionImp::info)) {
96 sid = static_cast<DeclaredFunctionImp*>(this)->body->sourceId();
97 lineno = static_cast<DeclaredFunctionImp*>(this)->body->firstLine();
98 }
99
100 bool cont = dbg->callEvent(&newExec,sid,lineno,this,args);
101 if (!cont) {
102 dbg->imp()->abort();
103 return Undefined();
104 }
105 }
106
107 Completion comp = execute(&newExec);
108
109 // if an exception occured, propogate it back to the previous execution object
110 if (newExec.hadException())
111 comp = Completion(Throw, newExec.exception());
112
113#ifdef KJS_VERBOSE
114 if (comp.complType() == Throw)
115 printInfo(exec,"throwing", comp.value());
116 else if (comp.complType() == ReturnValue)
117 printInfo(exec,"returning", comp.value());
118 else
119 fprintf(stderr, "returning: undefined\n");
120#endif
121
122 if (dbg) {
123 if (inherits(&DeclaredFunctionImp::info))
124 lineno = static_cast<DeclaredFunctionImp*>(this)->body->lastLine();
125
126 if (comp.complType() == Throw)
127 newExec.setException(comp.value());
128
129 int cont = dbg->returnEvent(&newExec,sid,lineno,this);
130 if (!cont) {
131 dbg->imp()->abort();
132 return Undefined();
133 }
134 }
135
136 if (comp.complType() == Throw) {
137 exec->setException(comp.value());
138 return comp.value();
139 }
140 else if (comp.complType() == ReturnValue)
141 return comp.value();
142 else
143 return Undefined();
144}
145
146void FunctionImp::addParameter(const Identifier &n)
147{
148 Parameter **p = &param;
149 while (*p)
150 p = &(*p)->next;
151
152 *p = new Parameter(n);
153}
154
155UString FunctionImp::parameterString() const
156{
157 UString s;
158 const Parameter *p = param;
159 while (p) {
160 if (!s.isEmpty())
161 s += ", ";
162 s += p->name.ustring();
163 p = p->next;
164 }
165
166 return s;
167}
168
169
170// ECMA 10.1.3q
171void FunctionImp::processParameters(ExecState *exec, const List &args)
172{
173 ObjectImp *variable = exec->context().imp()->variableObject();
174
175#ifdef KJS_VERBOSE
176 fprintf(stderr, "---------------------------------------------------\n"
177 "processing parameters for %s call\n",
178 name().isEmpty() ? "(internal)" : name().ascii());
179#endif
180
181 if (param) {
182 ListIterator it = args.begin();
183 Parameter *p = param;
184 while (p) {
185 if (it != args.end()) {
186#ifdef KJS_VERBOSE
187 fprintf(stderr, "setting parameter %s ", p->name.ascii());
188 printInfo(exec,"to", *it);
189#endif
190 variable->put(exec, p->name, *it);
191 it++;
192 } else
193 variable->put(exec, p->name, Undefined());
194 p = p->next;
195 }
196 }
197#ifdef KJS_VERBOSE
198 else {
199 for (int i = 0; i < args.size(); i++)
200 printInfo(exec,"setting argument", args[i]);
201 }
202#endif
203}
204
205void FunctionImp::processVarDecls(ExecState */*exec*/)
206{
207}
208
209ValueImp *FunctionImp::argumentsGetter(ExecState *exec, const Identifier& propertyName, const PropertySlot& slot)
210{
211 FunctionImp *thisObj = static_cast<FunctionImp *>(slot.slotBase());
212 ContextImp *context = exec->_context;
213 while (context) {
214 if (context->function() == thisObj) {
215 return static_cast<ActivationImp *>(context->activationObject())->get(exec, propertyName);
216 }
217 context = context->callingContext();
218 }
219 return Null();
220}
221
222ValueImp *FunctionImp::lengthGetter(ExecState *exec, const Identifier& propertyName, const PropertySlot& slot)
223{
224 FunctionImp *thisObj = static_cast<FunctionImp *>(slot.slotBase());
225 const Parameter *p = thisObj->param;
226 int count = 0;
227 while (p) {
228 ++count;
229 p = p->next;
230 }
231 return Number(count);
232}
233
234bool FunctionImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
235{
236 // Find the arguments from the closest context.
237 if (propertyName == exec->dynamicInterpreter()->argumentsIdentifier()) {
238 slot.setCustom(this, argumentsGetter);
239 return true;
240 }
241
242 // Compute length of parameters.
243 if (propertyName == lengthPropertyName) {
244 slot.setCustom(this, lengthGetter);
245 return true;
246 }
247
248 return InternalFunctionImp::getOwnPropertySlot(exec, propertyName, slot);
249}
250
251void FunctionImp::put(ExecState *exec, const Identifier &propertyName, ValueImp *value, int attr)
252{
253 if (propertyName == exec->dynamicInterpreter()->argumentsIdentifier() || propertyName == lengthPropertyName)
254 return;
255 InternalFunctionImp::put(exec, propertyName, value, attr);
256}
257
258bool FunctionImp::deleteProperty(ExecState *exec, const Identifier &propertyName)
259{
260 if (propertyName == exec->dynamicInterpreter()->argumentsIdentifier() || propertyName == lengthPropertyName)
261 return false;
262 return InternalFunctionImp::deleteProperty(exec, propertyName);
263}
264
265/* Returns the parameter name corresponding to the given index. eg:
266 * function f1(x, y, z): getParameterName(0) --> x
267 *
268 * If a name appears more than once, only the last index at which
269 * it appears associates with it. eg:
270 * function f2(x, x): getParameterName(0) --> null
271 */
272Identifier FunctionImp::getParameterName(int index)
273{
274 int i = 0;
275 Parameter *p = param;
276
277 if(!p)
278 return Identifier::null();
279
280 // skip to the parameter we want
281 while (i++ < index && (p = p->next))
282 ;
283
284 if (!p)
285 return Identifier::null();
286
287 Identifier name = p->name;
288
289 // Are there any subsequent parameters with the same name?
290 while ((p = p->next))
291 if (p->name == name)
292 return Identifier::null();
293
294 return name;
295}
296
297// ------------------------------ DeclaredFunctionImp --------------------------
298
299// ### is "Function" correct here?
300const ClassInfo DeclaredFunctionImp::info = {"Function", &FunctionImp::info, 0, 0};
301
302DeclaredFunctionImp::DeclaredFunctionImp(ExecState *exec, const Identifier &n,
303 FunctionBodyNode *b, const ScopeChain &sc)
304 : FunctionImp(exec,n), body(b)
305{
306 setScope(sc);
307}
308
309bool DeclaredFunctionImp::implementsConstruct() const
310{
311 return true;
312}
313
314// ECMA 13.2.2 [[Construct]]
315ObjectImp *DeclaredFunctionImp::construct(ExecState *exec, const List &args)
316{
317 ObjectImp *proto;
318 ValueImp *p = get(exec,prototypePropertyName);
319 if (p->isObject())
320 proto = static_cast<ObjectImp*>(p);
321 else
322 proto = exec->lexicalInterpreter()->builtinObjectPrototype();
323
324 ObjectImp *obj(new ObjectImp(proto));
325
326 ValueImp *res = call(exec,obj,args);
327
328 if (res->isObject())
329 return static_cast<ObjectImp *>(res);
330 else
331 return obj;
332}
333
334Completion DeclaredFunctionImp::execute(ExecState *exec)
335{
336 Completion result = body->execute(exec);
337
338 if (result.complType() == Throw || result.complType() == ReturnValue)
339 return result;
340 return Completion(Normal, Undefined()); // TODO: or ReturnValue ?
341}
342
343void DeclaredFunctionImp::processVarDecls(ExecState *exec)
344{
345 body->processVarDecls(exec);
346}
347
348// ------------------------------ IndexToNameMap ---------------------------------
349
350// We map indexes in the arguments array to their corresponding argument names.
351// Example: function f(x, y, z): arguments[0] = x, so we map 0 to Identifier("x").
352
353// Once we have an argument name, we can get and set the argument's value in the
354// activation object.
355
356// We use Identifier::null to indicate that a given argument's value
357// isn't stored in the activation object.
358
359IndexToNameMap::IndexToNameMap(FunctionImp *func, const List &args)
360{
361 _map = new Identifier[args.size()];
362 this->size = args.size();
363
364 int i = 0;
365 ListIterator iterator = args.begin();
366 for (; iterator != args.end(); i++, iterator++)
367 _map[i] = func->getParameterName(i); // null if there is no corresponding parameter
368}
369
370IndexToNameMap::~IndexToNameMap() {
371 delete [] _map;
372}
373
374bool IndexToNameMap::isMapped(const Identifier &index) const
375{
376 bool indexIsNumber;
377 int indexAsNumber = index.toUInt32(&indexIsNumber);
378
379 if (!indexIsNumber)
380 return false;
381
382 if (indexAsNumber >= size)
383 return false;
384
385 if (_map[indexAsNumber].isNull())
386 return false;
387
388 return true;
389}
390
391void IndexToNameMap::unMap(const Identifier &index)
392{
393 bool indexIsNumber;
394 int indexAsNumber = index.toUInt32(&indexIsNumber);
395
396 assert(indexIsNumber && indexAsNumber < size);
397
398 _map[indexAsNumber] = Identifier::null();
399}
400
401Identifier& IndexToNameMap::operator[](int index)
402{
403 return _map[index];
404}
405
406Identifier& IndexToNameMap::operator[](const Identifier &index)
407{
408 bool indexIsNumber;
409 int indexAsNumber = index.toUInt32(&indexIsNumber);
410
411 assert(indexIsNumber && indexAsNumber < size);
412
413 return (*this)[indexAsNumber];
414}
415
416// ------------------------------ ArgumentsImp ---------------------------------
417
418const ClassInfo ArgumentsImp::info = {"Arguments", 0, 0, 0};
419
420// ECMA 10.1.8
421ArgumentsImp::ArgumentsImp(ExecState *exec, FunctionImp *func, const List &args, ActivationImp *act)
422: ObjectImp(exec->lexicalInterpreter()->builtinObjectPrototype()),
423_activationObject(act),
424indexToNameMap(func, args)
425{
426 putDirect(calleePropertyName, func, DontEnum);
427 putDirect(lengthPropertyName, args.size(), DontEnum);
428
429 int i = 0;
430 ListIterator iterator = args.begin();
431 for (; iterator != args.end(); i++, iterator++) {
432 if (!indexToNameMap.isMapped(Identifier::from(i))) {
433 ObjectImp::put(exec, Identifier::from(i), *iterator, DontEnum);
434 }
435 }
436}
437
438void ArgumentsImp::mark()
439{
440 ObjectImp::mark();
441 if (_activationObject && !_activationObject->marked())
442 _activationObject->mark();
443}
444
445ValueImp *ArgumentsImp::mappedIndexGetter(ExecState *exec, const Identifier& propertyName, const PropertySlot& slot)
446{
447 ArgumentsImp *thisObj = static_cast<ArgumentsImp *>(slot.slotBase());
448 return thisObj->_activationObject->get(exec, thisObj->indexToNameMap[propertyName]);
449}
450
451bool ArgumentsImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
452{
453 if (indexToNameMap.isMapped(propertyName)) {
454 slot.setCustom(this, mappedIndexGetter);
455 return true;
456 }
457
458 return ObjectImp::getOwnPropertySlot(exec, propertyName, slot);
459}
460
461void ArgumentsImp::put(ExecState *exec, const Identifier &propertyName, ValueImp *value, int attr)
462{
463 if (indexToNameMap.isMapped(propertyName)) {
464 _activationObject->put(exec, indexToNameMap[propertyName], value, attr);
465 } else {
466 ObjectImp::put(exec, propertyName, value, attr);
467 }
468}
469
470bool ArgumentsImp::deleteProperty(ExecState *exec, const Identifier &propertyName)
471{
472 if (indexToNameMap.isMapped(propertyName)) {
473 indexToNameMap.unMap(propertyName);
474 return true;
475 } else {
476 return ObjectImp::deleteProperty(exec, propertyName);
477 }
478}
479
480// ------------------------------ ActivationImp --------------------------------
481
482const ClassInfo ActivationImp::info = {"Activation", 0, 0, 0};
483
484// ECMA 10.1.6
485ActivationImp::ActivationImp(FunctionImp *function, const List &arguments)
486 : _function(function), _arguments(true), _argumentsObject(0)
487{
488 _arguments = arguments.copy();
489 // FIXME: Do we need to support enumerating the arguments property?
490}
491
492ValueImp *ActivationImp::argumentsGetter(ExecState *exec, const Identifier& propertyName, const PropertySlot& slot)
493{
494 ActivationImp *thisObj = static_cast<ActivationImp *>(slot.slotBase());
495
496 // default: return builtin arguments array
497 if (!thisObj->_argumentsObject)
498 thisObj->createArgumentsObject(exec);
499
500 return thisObj->_argumentsObject;
501}
502
503PropertySlot::GetValueFunc ActivationImp::getArgumentsGetter()
504{
505 return ActivationImp::argumentsGetter;
506}
507
508bool ActivationImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
509{
510 // do this first so property map arguments property wins over the below
511 if (ObjectImp::getOwnPropertySlot(exec, propertyName, slot))
512 return true;
513
514 if (propertyName == exec->dynamicInterpreter()->argumentsIdentifier()) {
515 slot.setCustom(this, getArgumentsGetter());
516 return true;
517 }
518
519 return false;
520}
521
522bool ActivationImp::deleteProperty(ExecState *exec, const Identifier &propertyName)
523{
524 if (propertyName == exec->dynamicInterpreter()->argumentsIdentifier())
525 return false;
526 return ObjectImp::deleteProperty(exec, propertyName);
527}
528
529void ActivationImp::mark()
530{
531 if (_function && !_function->marked())
532 _function->mark();
533 _arguments.mark();
534 if (_argumentsObject && !_argumentsObject->marked())
535 _argumentsObject->mark();
536 ObjectImp::mark();
537}
538
539void ActivationImp::createArgumentsObject(ExecState *exec) const
540{
541 _argumentsObject = new ArgumentsImp(exec, _function, _arguments, const_cast<ActivationImp *>(this));
542}
543
544// ------------------------------ GlobalFunc -----------------------------------
545
546
547GlobalFuncImp::GlobalFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto, int i, int len)
548 : InternalFunctionImp(funcProto), id(i)
549{
550 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
551}
552
553CodeType GlobalFuncImp::codeType() const
554{
555 return id == Eval ? EvalCode : codeType();
556}
557
558bool GlobalFuncImp::implementsCall() const
559{
560 return true;
561}
562
563static ValueImp *encode(ExecState *exec, const List &args, const char *do_not_escape)
564{
565 UString r = "", s, str = args[0]->toString(exec);
566 CString cstr = str.UTF8String();
567 const char *p = cstr.c_str();
568 for (int k = 0; k < cstr.size(); k++, p++) {
569 char c = *p;
570 if (c && strchr(do_not_escape, c)) {
571 r.append(c);
572 } else {
573 char tmp[4];
574 sprintf(tmp, "%%%02X", (unsigned char)c);
575 r += tmp;
576 }
577 }
578 return String(r);
579}
580
581static ValueImp *decode(ExecState *exec, const List &args, const char *do_not_unescape, bool strict)
582{
583 UString s = "", str = args[0]->toString(exec);
584 int k = 0, len = str.size();
585 const UChar *d = str.data();
586 UChar u;
587 while (k < len) {
588 const UChar *p = d + k;
589 UChar c = *p;
590 if (c == '%') {
591 int charLen = 0;
592 if (k <= len - 3 && isxdigit(p[1].uc) && isxdigit(p[2].uc)) {
593 const char b0 = Lexer::convertHex(p[1].uc, p[2].uc);
594 const int sequenceLen = UTF8SequenceLength(b0);
595 if (sequenceLen != 0 && k <= len - sequenceLen * 3) {
596 charLen = sequenceLen * 3;
597 char sequence[5];
598 sequence[0] = b0;
599 for (int i = 1; i < sequenceLen; ++i) {
600 const UChar *q = p + i * 3;
601 if (q[0] == '%' && isxdigit(q[1].uc) && isxdigit(q[2].uc))
602 sequence[i] = Lexer::convertHex(q[1].uc, q[2].uc);
603 else {
604 charLen = 0;
605 break;
606 }
607 }
608 if (charLen != 0) {
609 sequence[sequenceLen] = 0;
610 const int character = decodeUTF8Sequence(sequence);
611 if (character < 0 || character >= 0x110000) {
612 charLen = 0;
613 } else if (character >= 0x10000) {
614 // Convert to surrogate pair.
615 s.append(static_cast<unsigned short>(0xD800 | ((character - 0x10000) >> 10)));
616 u = static_cast<unsigned short>(0xDC00 | ((character - 0x10000) & 0x3FF));
617 } else {
618 u = static_cast<unsigned short>(character);
619 }
620 }
621 }
622 }
623 if (charLen == 0) {
624 if (strict)
625 return throwError(exec, URIError);
626 // The only case where we don't use "strict" mode is the "unescape" function.
627 // For that, it's good to support the wonky "%u" syntax for compatibility with WinIE.
628 if (k <= len - 6 && p[1] == 'u'
629 && isxdigit(p[2].uc) && isxdigit(p[3].uc)
630 && isxdigit(p[4].uc) && isxdigit(p[5].uc)) {
631 charLen = 6;
632 u = Lexer::convertUnicode(p[2].uc, p[3].uc, p[4].uc, p[5].uc);
633 }
634 }
635 if (charLen && (u.uc == 0 || u.uc >= 128 || !strchr(do_not_unescape, u.low()))) {
636 c = u;
637 k += charLen - 1;
638 }
639 }
640 k++;
641 s.append(c);
642 }
643 return String(s);
644}
645
646static bool isStrWhiteSpace(unsigned short c)
647{
648 switch (c) {
649 case 0x0009:
650 case 0x000A:
651 case 0x000B:
652 case 0x000C:
653 case 0x000D:
654 case 0x0020:
655 case 0x00A0:
656 case 0x2028:
657 case 0x2029:
658 return true;
659 default:
660 return u_charType(c) == U_SPACE_SEPARATOR;
661 }
662}
663
664static int parseDigit(unsigned short c, int radix)
665{
666 int digit = -1;
667
668 if (c >= '0' && c <= '9') {
669 digit = c - '0';
670 } else if (c >= 'A' && c <= 'Z') {
671 digit = c - 'A' + 10;
672 } else if (c >= 'a' && c <= 'z') {
673 digit = c - 'a' + 10;
674 }
675
676 if (digit >= radix)
677 return -1;
678 return digit;
679}
680
681static double parseInt(const UString &s, int radix)
682{
683 int length = s.size();
684 int p = 0;
685
686 while (p < length && isStrWhiteSpace(s[p].uc)) {
687 ++p;
688 }
689
690 double sign = 1;
691 if (p < length) {
692 if (s[p] == '+') {
693 ++p;
694 } else if (s[p] == '-') {
695 sign = -1;
696 ++p;
697 }
698 }
699
700 if ((radix == 0 || radix == 16) && length - p >= 2 && s[p] == '0' && (s[p + 1] == 'x' || s[p + 1] == 'X')) {
701 radix = 16;
702 p += 2;
703 } else if (radix == 0) {
704 if (p < length && s[p] == '0')
705 radix = 8;
706 else
707 radix = 10;
708 }
709
710 if (radix < 2 || radix > 36)
711 return NaN;
712
713 bool sawDigit = false;
714 double number = 0;
715 while (p < length) {
716 int digit = parseDigit(s[p].uc, radix);
717 if (digit == -1)
718 break;
719 sawDigit = true;
720 number *= radix;
721 number += digit;
722 ++p;
723 }
724
725 if (!sawDigit)
726 return NaN;
727
728 return sign * number;
729}
730
731static double parseFloat(const UString &s)
732{
733 // Check for 0x prefix here, because toDouble allows it, but we must treat it as 0.
734 // Need to skip any whitespace and then one + or - sign.
735 int length = s.size();
736 int p = 0;
737 while (p < length && isStrWhiteSpace(s[p].uc)) {
738 ++p;
739 }
740 if (p < length && (s[p] == '+' || s[p] == '-')) {
741 ++p;
742 }
743 if (length - p >= 2 && s[p] == '0' && (s[p + 1] == 'x' || s[p + 1] == 'X')) {
744 return 0;
745 }
746
747 return s.toDouble( true /*tolerant*/, false /* NaN for empty string */ );
748}
749
750ValueImp *GlobalFuncImp::callAsFunction(ExecState *exec, ObjectImp */*thisObj*/, const List &args)
751{
752 ValueImp *res = jsUndefined();
753
754 static const char do_not_escape[] =
755 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
756 "abcdefghijklmnopqrstuvwxyz"
757 "0123456789"
758 "*+-./@_";
759
760 static const char do_not_escape_when_encoding_URI_component[] =
761 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
762 "abcdefghijklmnopqrstuvwxyz"
763 "0123456789"
764 "!'()*-._~";
765 static const char do_not_escape_when_encoding_URI[] =
766 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
767 "abcdefghijklmnopqrstuvwxyz"
768 "0123456789"
769 "!#$&'()*+,-./:;=?@_~";
770 static const char do_not_unescape_when_decoding_URI[] =
771 "#$&+,/:;=?@";
772
773 switch (id) {
774 case Eval: { // eval()
775 ValueImp *x = args[0];
776 if (!x->isString())
777 return x;
778 else {
779 UString s = x->toString(exec);
780
781 int sid;
782 int errLine;
783 UString errMsg;
784 RefPtr<ProgramNode> progNode(Parser::parse(UString(), 0, s.data(),s.size(),&sid,&errLine,&errMsg));
785
786 Debugger *dbg = exec->dynamicInterpreter()->imp()->debugger();
787 if (dbg) {
788 bool cont = dbg->sourceParsed(exec, sid, UString(), s, errLine);
789 if (!cont)
790 return Undefined();
791 }
792
793 // no program node means a syntax occurred
794 if (!progNode) {
795 return throwError(exec, SyntaxError, errMsg, errLine, sid, NULL);
796 }
797
798 // enter a new execution context
799 ObjectImp *thisVal = static_cast<ObjectImp *>(exec->context().thisValue());
800 ContextImp ctx(exec->dynamicInterpreter()->globalObject(),
801 exec->dynamicInterpreter()->imp(),
802 thisVal,
803 EvalCode,
804 exec->context().imp());
805
806 ExecState newExec(exec->dynamicInterpreter(), &ctx);
807 newExec.setException(exec->exception()); // could be null
808
809 // execute the code
810 progNode->processVarDecls(&newExec);
811 Completion c = progNode->execute(&newExec);
812
813 // if an exception occured, propogate it back to the previous execution object
814 if (newExec.hadException())
815 exec->setException(newExec.exception());
816
817 res = Undefined();
818 if (c.complType() == Throw)
819 exec->setException(c.value());
820 else if (c.isValueCompletion())
821 res = c.value();
822 }
823 break;
824 }
825 case ParseInt:
826 res = Number(parseInt(args[0]->toString(exec), args[1]->toInt32(exec)));
827 break;
828 case ParseFloat:
829 res = Number(parseFloat(args[0]->toString(exec)));
830 break;
831 case IsNaN:
832 res = Boolean(isNaN(args[0]->toNumber(exec)));
833 break;
834 case IsFinite: {
835 double n = args[0]->toNumber(exec);
836 res = Boolean(!isNaN(n) && !isInf(n));
837 break;
838 }
839 case DecodeURI:
840 res = decode(exec, args, do_not_unescape_when_decoding_URI, true);
841 break;
842 case DecodeURIComponent:
843 res = decode(exec, args, "", true);
844 break;
845 case EncodeURI:
846 res = encode(exec, args, do_not_escape_when_encoding_URI);
847 break;
848 case EncodeURIComponent:
849 res = encode(exec, args, do_not_escape_when_encoding_URI_component);
850 break;
851 case Escape:
852 {
853 UString r = "", s, str = args[0]->toString(exec);
854 const UChar *c = str.data();
855 for (int k = 0; k < str.size(); k++, c++) {
856 int u = c->uc;
857 if (u > 255) {
858 char tmp[7];
859 sprintf(tmp, "%%u%04X", u);
860 s = UString(tmp);
861 } else if (u != 0 && strchr(do_not_escape, (char)u)) {
862 s = UString(c, 1);
863 } else {
864 char tmp[4];
865 sprintf(tmp, "%%%02X", u);
866 s = UString(tmp);
867 }
868 r += s;
869 }
870 res = String(r);
871 break;
872 }
873 case UnEscape:
874 {
875 UString s = "", str = args[0]->toString(exec);
876 int k = 0, len = str.size();
877 while (k < len) {
878 const UChar *c = str.data() + k;
879 UChar u;
880 if (*c == UChar('%') && k <= len - 6 && *(c+1) == UChar('u')) {
881 if (Lexer::isHexDigit((c+2)->uc) && Lexer::isHexDigit((c+3)->uc) &&
882 Lexer::isHexDigit((c+4)->uc) && Lexer::isHexDigit((c+5)->uc)) {
883 u = Lexer::convertUnicode((c+2)->uc, (c+3)->uc,
884 (c+4)->uc, (c+5)->uc);
885 c = &u;
886 k += 5;
887 }
888 } else if (*c == UChar('%') && k <= len - 3 &&
889 Lexer::isHexDigit((c+1)->uc) && Lexer::isHexDigit((c+2)->uc)) {
890 u = UChar(Lexer::convertHex((c+1)->uc, (c+2)->uc));
891 c = &u;
892 k += 2;
893 }
894 k++;
895 s += UString(c, 1);
896 }
897 res = String(s);
898 break;
899 }
900#ifndef NDEBUG
901 case KJSPrint:
902 puts(args[0]->toString(exec).ascii());
903 break;
904#endif
905 }
906
907 return res;
908}
909
910} // namespace
Note: See TracBrowser for help on using the repository browser.