source: webkit/trunk/JavaScriptCore/kjs/object.cpp@ 6717

Last change on this file since 6717 was 6717, checked in by kdecker, 21 years ago

JavaScriptCore:

Reviewed by Ken.

-revised generated error message content

  • kjs/error_object.cpp: (ErrorProtoFuncImp::call):
  • kjs/internal.cpp: (Parser::parse):
  • kjs/object.cpp: (KJS::Error::create):

WebCore:

Reviewed by Ken.

-wired up JavaScript error message handling to
the WebCoreBridge

  • khtml/ecma/kjs_events.cpp: (JSEventListener::handleEvent):
  • khtml/ecma/kjs_proxy.cpp: (KJSProxyImpl::evaluate):
  • khtml/ecma/kjs_window.cpp: (Window::isSafeScript): (ScheduledAction::execute):
  • kwq/KWQKHTMLPart.h:
  • kwq/KWQKHTMLPart.mm: (KWQKHTMLPart::addMessageToConsole):
  • kwq/WebCoreBridge.h:
  • kwq/WebCoreBridge.mm:

WebKit:

Reviewed by Ken.

-wired up JavaScript error message handling through
the WebCoreBridge

  • WebCoreSupport.subproj/WebBridge.m: (-[WebBridge addMessageToConsole:]):
  • WebKit.pbproj/project.pbxproj:
  • WebView.subproj/WebUIDelegatePrivate.h:

WebBrowser:

Reviewed by Ken.

-added the JavaScript Console feature

  • BrowserWebController.m: (-[BrowserWebView setWindowFocusDisabled:]): (-[BrowserWebView webView:addMessageToConsole:]):
  • Debug/DebugUtilities.m: (-[DebugUtilities createDebugMenu]): (-[BrowserDocument showJavaScriptConsole:]):
  • WebBrowser.pbproj/project.pbxproj:
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.4 KB
Line 
1// -*- c-basic-offset: 2 -*-
2/*
3 * This file is part of the KDE libraries
4 * Copyright (C) 1999-2001 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., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
22 *
23 */
24
25#include "value.h"
26#include "object.h"
27#include "types.h"
28#include "interpreter.h"
29#include "lookup.h"
30#include "reference_list.h"
31
32#include <assert.h>
33#include <math.h>
34#include <stdio.h>
35
36#include "internal.h"
37#include "collector.h"
38#include "operations.h"
39#include "error_object.h"
40#include "nodes.h"
41
42namespace KJS {
43
44// ------------------------------ Object ---------------------------------------
45
46Object Object::dynamicCast(const Value &v)
47{
48 if (v.isNull() || v.type() != ObjectType)
49 return Object(0);
50
51 return Object(static_cast<ObjectImp*>(v.imp()));
52}
53
54
55Value Object::call(ExecState *exec, Object &thisObj, const List &args)
56{
57#if KJS_MAX_STACK > 0
58 static int depth = 0; // sum of all concurrent interpreters
59 if (++depth > KJS_MAX_STACK) {
60 --depth;
61 Object err = Error::create(exec, RangeError,
62 "Maximum call stack size exceeded.");
63 exec->setException(err);
64 return err;
65 }
66#endif
67
68 Value ret = imp()->call(exec,thisObj,args);
69
70#if KJS_MAX_STACK > 0
71 --depth;
72#endif
73
74 return ret;
75}
76
77// ------------------------------ ObjectImp ------------------------------------
78
79ObjectImp::ObjectImp(const Object &proto)
80 : _proto(static_cast<ObjectImp*>(proto.imp())), _internalValue(0L)
81{
82 //fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);
83}
84
85ObjectImp::ObjectImp(ObjectImp *proto)
86 : _proto(proto), _internalValue(0L)
87{
88 //fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);
89}
90
91ObjectImp::ObjectImp()
92{
93 //fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);
94 _proto = NullImp::staticNull;
95 _internalValue = 0L;
96}
97
98ObjectImp::~ObjectImp()
99{
100 //fprintf(stderr,"ObjectImp::~ObjectImp %p\n",(void*)this);
101}
102
103void ObjectImp::mark()
104{
105 //fprintf(stderr,"ObjectImp::mark() %p\n",(void*)this);
106 ValueImp::mark();
107
108 if (_proto && !_proto->marked())
109 _proto->mark();
110
111 _prop.mark();
112
113 if (_internalValue && !_internalValue->marked())
114 _internalValue->mark();
115
116 _scope.mark();
117}
118
119const ClassInfo *ObjectImp::classInfo() const
120{
121 return 0;
122}
123
124bool ObjectImp::inherits(const ClassInfo *info) const
125{
126 if (!info)
127 return false;
128
129 const ClassInfo *ci = classInfo();
130 if (!ci)
131 return false;
132
133 while (ci && ci != info)
134 ci = ci->parentClass;
135
136 return (ci == info);
137}
138
139Type ObjectImp::type() const
140{
141 return ObjectType;
142}
143
144Value ObjectImp::prototype() const
145{
146 return Value(_proto);
147}
148
149void ObjectImp::setPrototype(const Value &proto)
150{
151 _proto = proto.imp();
152}
153
154UString ObjectImp::className() const
155{
156 const ClassInfo *ci = classInfo();
157 if ( ci )
158 return ci->className;
159 return "Object";
160}
161
162Value ObjectImp::get(ExecState *exec, const Identifier &propertyName) const
163{
164 ValueImp *imp = getDirect(propertyName);
165 if (imp)
166 return Value(imp);
167
168 // non-standard netscape extension
169 if (propertyName == specialPrototypePropertyName)
170 return Value(_proto);
171
172 if (_proto->dispatchType() != ObjectType) {
173 return Undefined();
174 }
175
176 return static_cast<ObjectImp *>(_proto)->get(exec, propertyName);
177}
178
179Value ObjectImp::get(ExecState *exec, unsigned propertyName) const
180{
181 return get(exec, Identifier::from(propertyName));
182}
183
184// ECMA 8.6.2.2
185void ObjectImp::put(ExecState *exec, const Identifier &propertyName,
186 const Value &value, int attr)
187{
188 assert(!value.isNull());
189
190 // non-standard netscape extension
191 if (propertyName == specialPrototypePropertyName) {
192 setPrototype(value);
193 return;
194 }
195
196 /* TODO: check for write permissions directly w/o this call */
197 /* Doesn't look very easy with the PropertyMap API - David */
198 // putValue() is used for JS assignemnts. It passes no attribute.
199 // Assume that a C++ implementation knows what it is doing
200 // and let it override the canPut() check.
201 if ((attr == None || attr == DontDelete) && !canPut(exec,propertyName)) {
202#ifdef KJS_VERBOSE
203 fprintf( stderr, "WARNING: canPut %s said NO\n", propertyName.ascii() );
204#endif
205 return;
206 }
207
208 _prop.put(propertyName,value.imp(),attr);
209}
210
211void ObjectImp::put(ExecState *exec, unsigned propertyName,
212 const Value &value, int attr)
213{
214 put(exec, Identifier::from(propertyName), value, attr);
215}
216
217// ECMA 8.6.2.3
218bool ObjectImp::canPut(ExecState *, const Identifier &propertyName) const
219{
220 int attributes;
221 ValueImp *v = _prop.get(propertyName, attributes);
222 if (v)
223 return!(attributes & ReadOnly);
224
225 // Look in the static hashtable of properties
226 const HashEntry* e = findPropertyHashEntry(propertyName);
227 if (e)
228 return !(e->attr & ReadOnly);
229
230 // Don't look in the prototype here. We can always put an override
231 // in the object, even if the prototype has a ReadOnly property.
232 return true;
233}
234
235// ECMA 8.6.2.4
236bool ObjectImp::hasProperty(ExecState *exec, const Identifier &propertyName) const
237{
238 if (_prop.get(propertyName))
239 return true;
240
241 // Look in the static hashtable of properties
242 if (findPropertyHashEntry(propertyName))
243 return true;
244
245 // non-standard netscape extension
246 if (propertyName == specialPrototypePropertyName)
247 return true;
248
249 if (_proto->dispatchType() != ObjectType) {
250 return false;
251 }
252
253 // Look in the prototype
254 return static_cast<ObjectImp *>(_proto)->hasProperty(exec, propertyName);
255}
256
257bool ObjectImp::hasProperty(ExecState *exec, unsigned propertyName) const
258{
259 return hasProperty(exec, Identifier::from(propertyName));
260}
261
262// ECMA 8.6.2.5
263bool ObjectImp::deleteProperty(ExecState */*exec*/, const Identifier &propertyName)
264{
265 int attributes;
266 ValueImp *v = _prop.get(propertyName, attributes);
267 if (v) {
268 if ((attributes & DontDelete))
269 return false;
270 _prop.remove(propertyName);
271 return true;
272 }
273
274 // Look in the static hashtable of properties
275 const HashEntry* entry = findPropertyHashEntry(propertyName);
276 if (entry && entry->attr & DontDelete)
277 return false; // this builtin property can't be deleted
278 return true;
279}
280
281bool ObjectImp::deleteProperty(ExecState *exec, unsigned propertyName)
282{
283 return deleteProperty(exec, Identifier::from(propertyName));
284}
285
286void ObjectImp::deleteAllProperties( ExecState * )
287{
288 _prop.clear();
289}
290
291// ECMA 8.6.2.6
292Value ObjectImp::defaultValue(ExecState *exec, Type hint) const
293{
294 if (hint != StringType && hint != NumberType) {
295 /* Prefer String for Date objects */
296 if (_proto == exec->lexicalInterpreter()->builtinDatePrototype().imp())
297 hint = StringType;
298 else
299 hint = NumberType;
300 }
301
302 Value v;
303 if (hint == StringType)
304 v = get(exec,toStringPropertyName);
305 else
306 v = get(exec,valueOfPropertyName);
307
308 if (v.type() == ObjectType) {
309 Object o = Object(static_cast<ObjectImp*>(v.imp()));
310 if (o.implementsCall()) { // spec says "not primitive type" but ...
311 Object thisObj = Object(const_cast<ObjectImp*>(this));
312 Value def = o.call(exec,thisObj,List::empty());
313 Type defType = def.type();
314 if (defType == UnspecifiedType || defType == UndefinedType ||
315 defType == NullType || defType == BooleanType ||
316 defType == StringType || defType == NumberType) {
317 return def;
318 }
319 }
320 }
321
322 if (hint == StringType)
323 v = get(exec,valueOfPropertyName);
324 else
325 v = get(exec,toStringPropertyName);
326
327 if (v.type() == ObjectType) {
328 Object o = Object(static_cast<ObjectImp*>(v.imp()));
329 if (o.implementsCall()) { // spec says "not primitive type" but ...
330 Object thisObj = Object(const_cast<ObjectImp*>(this));
331 Value def = o.call(exec,thisObj,List::empty());
332 Type defType = def.type();
333 if (defType == UnspecifiedType || defType == UndefinedType ||
334 defType == NullType || defType == BooleanType ||
335 defType == StringType || defType == NumberType) {
336 return def;
337 }
338 }
339 }
340
341 Object err = Error::create(exec, TypeError, I18N_NOOP("No default value"));
342 exec->setException(err);
343 return err;
344}
345
346const HashEntry* ObjectImp::findPropertyHashEntry( const Identifier& propertyName ) const
347{
348 const ClassInfo *info = classInfo();
349 while (info) {
350 if (info->propHashTable) {
351 const HashEntry *e = Lookup::findEntry(info->propHashTable, propertyName);
352 if (e)
353 return e;
354 }
355 info = info->parentClass;
356 }
357 return 0L;
358}
359
360bool ObjectImp::implementsConstruct() const
361{
362 return false;
363}
364
365Object ObjectImp::construct(ExecState */*exec*/, const List &/*args*/)
366{
367 assert(false);
368 return Object(0);
369}
370
371bool ObjectImp::implementsCall() const
372{
373 return false;
374}
375
376Value ObjectImp::call(ExecState */*exec*/, Object &/*thisObj*/, const List &/*args*/)
377{
378 assert(false);
379 return Object(0);
380}
381
382bool ObjectImp::implementsHasInstance() const
383{
384 return false;
385}
386
387Boolean ObjectImp::hasInstance(ExecState */*exec*/, const Value &/*value*/)
388{
389 assert(false);
390 return Boolean(false);
391}
392
393ReferenceList ObjectImp::propList(ExecState *exec, bool recursive)
394{
395 ReferenceList list;
396 if (_proto && _proto->dispatchType() == ObjectType && recursive)
397 list = static_cast<ObjectImp*>(_proto)->propList(exec,recursive);
398
399 _prop.addEnumerablesToReferenceList(list, Object(this));
400
401 // Add properties from the static hashtable of properties
402 const ClassInfo *info = classInfo();
403 while (info) {
404 if (info->propHashTable) {
405 int size = info->propHashTable->size;
406 const HashEntry *e = info->propHashTable->entries;
407 for (int i = 0; i < size; ++i, ++e) {
408 if ( e->s && !(e->attr & DontEnum) )
409 list.append(Reference(this, e->s)); /// ######### check for duplicates with the propertymap
410 }
411 }
412 info = info->parentClass;
413 }
414
415 return list;
416}
417
418Value ObjectImp::internalValue() const
419{
420 return Value(_internalValue);
421}
422
423void ObjectImp::setInternalValue(const Value &v)
424{
425 _internalValue = v.imp();
426}
427
428void ObjectImp::setInternalValue(ValueImp *v)
429{
430#if !USE_CONSERVATIVE_GC
431 v->setGcAllowed();
432#endif
433 _internalValue = v;
434}
435
436Value ObjectImp::toPrimitive(ExecState *exec, Type preferredType) const
437{
438 return defaultValue(exec,preferredType);
439}
440
441bool ObjectImp::toBoolean(ExecState */*exec*/) const
442{
443 return true;
444}
445
446double ObjectImp::toNumber(ExecState *exec) const
447{
448 Value prim = toPrimitive(exec,NumberType);
449 if (exec->hadException()) // should be picked up soon in nodes.cpp
450 return 0.0;
451 return prim.toNumber(exec);
452}
453
454UString ObjectImp::toString(ExecState *exec) const
455{
456 Value prim = toPrimitive(exec,StringType);
457 if (exec->hadException()) // should be picked up soon in nodes.cpp
458 return "";
459 return prim.toString(exec);
460}
461
462Object ObjectImp::toObject(ExecState */*exec*/) const
463{
464 return Object(const_cast<ObjectImp*>(this));
465}
466
467void ObjectImp::putDirect(const Identifier &propertyName, ValueImp *value, int attr)
468{
469#if !USE_CONSERVATIVE_GC
470 value->setGcAllowed();
471#endif
472 _prop.put(propertyName, value, attr);
473}
474
475void ObjectImp::putDirect(const Identifier &propertyName, int value, int attr)
476{
477 _prop.put(propertyName, NumberImp::create(value), attr);
478}
479
480// ------------------------------ Error ----------------------------------------
481
482const char * const errorNamesArr[] = {
483 I18N_NOOP("Error"), // GeneralError
484 I18N_NOOP("Evaluation error"), // EvalError
485 I18N_NOOP("Range error"), // RangeError
486 I18N_NOOP("Reference error"), // ReferenceError
487 I18N_NOOP("Syntax error"), // SyntaxError
488 I18N_NOOP("Type error"), // TypeError
489 I18N_NOOP("URI error"), // URIError
490};
491
492const char * const * const Error::errorNames = errorNamesArr;
493
494Object Error::create(ExecState *exec, ErrorType errtype, const char *message,
495 int lineno, int sourceId)
496{
497 Object cons;
498 switch (errtype) {
499 case EvalError:
500 cons = exec->lexicalInterpreter()->builtinEvalError();
501 break;
502 case RangeError:
503 cons = exec->lexicalInterpreter()->builtinRangeError();
504 break;
505 case ReferenceError:
506 cons = exec->lexicalInterpreter()->builtinReferenceError();
507 break;
508 case SyntaxError:
509 cons = exec->lexicalInterpreter()->builtinSyntaxError();
510 break;
511 case TypeError:
512 cons = exec->lexicalInterpreter()->builtinTypeError();
513 break;
514 case URIError:
515 cons = exec->lexicalInterpreter()->builtinURIError();
516 break;
517 default:
518 cons = exec->lexicalInterpreter()->builtinError();
519 break;
520 }
521
522 if (!message)
523 message = errorNames[errtype];
524 List args;
525 args.append(String(message));
526 Object err = Object::dynamicCast(cons.construct(exec,args));
527
528 if (lineno != -1)
529 err.put(exec, "line", Number(lineno));
530 if (sourceId != -1)
531 err.put(exec, "sourceId", Number(sourceId));
532
533 return err;
534
535/*
536#ifndef NDEBUG
537 const char *msg = err.get("message").toString().value().ascii();
538 if (l >= 0)
539 fprintf(stderr, "KJS: %s at line %d. %s\n", estr, l, msg);
540 else
541 fprintf(stderr, "KJS: %s. %s\n", estr, msg);
542#endif
543
544 return err;
545*/
546}
547
548} // namespace KJS
Note: See TracBrowser for help on using the repository browser.