Added exception logging. Also check for exception and
[WebKit-https.git] / JavaScriptCore / bindings / objc / WebScriptObject.mm
1 /*
2  * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25 #import <JavaScriptCore/WebScriptObjectPrivate.h>
26
27 #include <JavaScriptCore/internal.h>
28 #include <JavaScriptCore/list.h>
29 #include <JavaScriptCore/value.h>
30
31 #include <objc_jsobject.h>
32 #include <objc_instance.h>
33 #include <objc_utility.h>
34
35 #include <runtime_object.h>
36 #include <runtime_root.h>
37
38 using namespace KJS;
39 using namespace KJS::Bindings;
40
41 #define LOG_EXCEPTION(exec) \
42     if (Interpreter::shouldPrintExceptions()) \
43         NSLog (@"%s:%d:  JavaScript exception:  %s\n", __FILE__, __LINE__, exec->exception().toObject(exec).get(exec, messagePropertyName).toString(exec).ascii());
44
45 @interface WebScriptObjectPrivate : NSObject
46 {
47     KJS::ObjectImp *imp;
48     const Bindings::RootObject *root;
49 }
50 @end
51
52 @implementation WebScriptObjectPrivate
53 @end
54
55 @implementation WebScriptObject
56
57 static void _didExecute(WebScriptObject *obj)
58 {
59     ExecState *exec = obj->_private->root->interpreter()->globalExec();
60     KJSDidExecuteFunctionPtr func = Instance::didExecuteFunction();
61     if (func)
62         func (exec, static_cast<KJS::ObjectImp*>(obj->_private->root->rootObjectImp()));
63 }
64
65 - _initWithObjectImp:(KJS::ObjectImp *)imp root:(const Bindings::RootObject *)root
66 {
67     assert (imp != 0);
68     //assert (root != 0);
69
70     self = [super init];
71
72     _private = [[WebScriptObjectPrivate alloc] init];
73     _private->imp = imp;
74     _private->root = root;    
75
76     addNativeReference (root, imp);
77     
78     return self;
79 }
80
81 - (KJS::ObjectImp *)_imp
82 {
83     return _private->imp;
84 }
85
86 - (void)dealloc
87 {
88     if (_private)
89         removeNativeReference (_private->imp);
90     [_private release];
91     [super dealloc];
92 }
93
94 + (BOOL)throwException:(NSString *)exceptionMessage
95 {
96     NSLog (@"%s:%d:  not yet implemented", __PRETTY_FUNCTION__, __LINE__);
97     return NO;
98 }
99
100 static KJS::List listFromNSArray(ExecState *exec, NSArray *array)
101 {
102     long i, numObjects = array ? [array count] : 0;
103     KJS::List aList;
104     
105     for (i = 0; i < numObjects; i++) {
106         id anObject = [array objectAtIndex:i];
107         aList.append (convertObjcValueToValue(exec, &anObject, ObjcObjectType));
108     }
109     return aList;
110 }
111
112 - (id)callWebScriptMethod:(NSString *)name withArguments:(NSArray *)args
113 {
114     // Lookup the function object.
115     ExecState *exec = _private->root->interpreter()->globalExec();
116     Interpreter::lock();
117     
118     Value v = convertObjcValueToValue(exec, &name, ObjcObjectType);
119     Identifier identifier(v.toString(exec));
120     Value func = _private->imp->get (exec, identifier);
121     Interpreter::unlock();
122     if (func.isNull() || func.type() == UndefinedType) {
123         // Maybe throw an exception here?
124         return 0;
125     }
126
127     // Call the function object.    
128     Interpreter::lock();
129     ObjectImp *funcImp = static_cast<ObjectImp*>(func.imp());
130     Object thisObj = Object(const_cast<ObjectImp*>(_private->imp));
131     List argList = listFromNSArray(exec, args);
132     Value result = funcImp->call (exec, thisObj, argList);
133     Interpreter::unlock();
134
135     if (exec->hadException()) {
136         LOG_EXCEPTION (exec);
137         result = Undefined();
138     }
139
140     // Convert and return the result of the function call.
141     id resultObj = [WebScriptObject _convertValueToObjcValue:result root:_private->root];
142
143     _didExecute(self);
144         
145     return resultObj;
146 }
147
148 - (id)evaluateWebScript:(NSString *)script
149 {
150     ExecState *exec = _private->root->interpreter()->globalExec();
151     Object thisObj = Object(const_cast<ObjectImp*>(_private->imp));
152     Interpreter::lock();
153     Value v = convertObjcValueToValue(exec, &script, ObjcObjectType);
154     KJS::Value result = _private->root->interpreter()->evaluate(v.toString(exec)).value();
155     Interpreter::unlock();
156     
157     if (exec->hadException()) {
158         LOG_EXCEPTION (exec);
159         result = Undefined();
160     }
161
162     id resultObj = [WebScriptObject _convertValueToObjcValue:result root:_private->root];
163
164     _didExecute(self);
165     
166     return resultObj;
167 }
168
169 - (void)setValue:(id)value forKey:(NSString *)key
170 {
171     ExecState *exec = _private->root->interpreter()->globalExec();
172     Interpreter::lock();
173     Value v = convertObjcValueToValue(exec, &key, ObjcObjectType);
174    _private->imp->put (exec, Identifier (v.toString(exec)), (convertObjcValueToValue(exec, &value, ObjcObjectType)));
175     Interpreter::unlock();
176
177     if (exec->hadException()) {
178         LOG_EXCEPTION (exec);
179     }
180
181     _didExecute(self);
182 }
183
184 - (id)valueForKey:(NSString *)key
185 {
186     ExecState *exec = _private->root->interpreter()->globalExec();
187     Interpreter::lock();
188     Value v = convertObjcValueToValue(exec, &key, ObjcObjectType);
189     Value result = _private->imp->get (exec, Identifier (v.toString(exec)));
190     Interpreter::unlock();
191     
192     if (exec->hadException()) {
193         LOG_EXCEPTION (exec);
194         result = Undefined();
195     }
196
197     id resultObj = [WebScriptObject _convertValueToObjcValue:result root:_private->root];
198
199     _didExecute(self);
200     
201     return resultObj;
202 }
203
204 - (void)removeWebScriptKey:(NSString *)key;
205 {
206     ExecState *exec = _private->root->interpreter()->globalExec();
207     Interpreter::lock();
208     Value v = convertObjcValueToValue(exec, &key, ObjcObjectType);
209     _private->imp->deleteProperty (exec, Identifier (v.toString(exec)));
210     Interpreter::unlock();
211
212     if (exec->hadException()) {
213         LOG_EXCEPTION (exec);
214     }
215
216     _didExecute(self);
217 }
218
219 - (NSString *)stringRepresentation
220 {
221     Interpreter::lock();
222     Object thisObj = Object(const_cast<ObjectImp*>(_private->imp));
223     ExecState *exec = _private->root->interpreter()->globalExec();
224     
225     id result = convertValueToObjcValue(exec, thisObj, ObjcObjectType).objectValue;
226
227     Interpreter::unlock();
228     
229     id resultObj = [result description];
230
231     _didExecute(self);
232
233     return resultObj;
234 }
235
236 - (id)webScriptValueAtIndex:(unsigned int)index;
237 {
238     ExecState *exec = _private->root->interpreter()->globalExec();
239     Interpreter::lock();
240     Value result = _private->imp->get (exec, (unsigned)index);
241     Interpreter::unlock();
242
243     if (exec->hadException()) {
244         LOG_EXCEPTION (exec);
245         result = Undefined();
246     }
247
248     id resultObj = [WebScriptObject _convertValueToObjcValue:result root:_private->root];
249
250     _didExecute(self);
251
252     return resultObj;
253 }
254
255 - (void)setWebScriptValueAtIndex:(unsigned int)index value:(id)value;
256 {
257     ExecState *exec = _private->root->interpreter()->globalExec();
258     Interpreter::lock();
259     _private->imp->put (exec, (unsigned)index, (convertObjcValueToValue(exec, &value, ObjcObjectType)));
260     Interpreter::unlock();
261
262     if (exec->hadException()) {
263         LOG_EXCEPTION (exec);
264     }
265
266     _didExecute(self);
267 }
268
269 - (void)setException: (NSString *)description;
270 {
271     ExecState *exec = _private->root->interpreter()->globalExec();
272     Object err = Error::create(exec, GeneralError, [description UTF8String]);
273     exec->setException (err);
274 }
275
276 + (id)_convertValueToObjcValue:(KJS::Value)value root:(const Bindings::RootObject *)root
277 {
278     id result = 0;
279
280     // First see if we have a ObjC instance.
281     if (value.type() == KJS::ObjectType){
282         ObjectImp *objectImp = static_cast<ObjectImp*>(value.imp());
283         if (strcmp(objectImp->classInfo()->className, "RuntimeObject") == 0) {
284             RuntimeObjectImp *imp = static_cast<RuntimeObjectImp *>(value.imp());
285             ObjcInstance *instance = static_cast<ObjcInstance*>(imp->getInternalInstance());
286             if (instance)
287                 result = instance->getObject();
288         }
289         // Convert to a WebScriptObject
290         else {
291             result = [[[WebScriptObject alloc] _initWithObjectImp:objectImp root:root] autorelease];
292         }
293     }
294     
295     // Convert JavaScript String value to NSString?
296     else if (value.type() == KJS::StringType) {
297         StringImp *s = static_cast<KJS::StringImp*>(value.imp());
298         UString u = s->value();
299         
300         NSString *string = [NSString stringWithCharacters:(const unichar*)u.data() length:u.size()];
301         result = string;
302     }
303     
304     // Convert JavaScript Number value to NSNumber?
305     else if (value.type() == KJS::NumberType) {
306         Number n = Number::dynamicCast(value);
307         result = [NSNumber numberWithDouble:n.value()];
308     }
309     
310     // Boolean?
311     return result;
312 }
313
314 @end
315
316
317 @implementation WebUndefined
318
319 static WebUndefined *sharedUndefined = 0;
320
321 + (WebUndefined *)undefined
322 {
323     if (!sharedUndefined)
324         sharedUndefined = [[WebUndefined alloc] init];
325     return sharedUndefined;
326 }
327
328 - (id)initWithCoder:(NSCoder *)coder
329 {
330     return [WebUndefined undefined];
331 }
332
333 - (void)encodeWithCoder:(NSCoder *)encoder
334 {
335 }
336
337 - (id)copyWithZone:(NSZone *)zone
338 {
339     return [WebUndefined undefined];
340 }
341
342 - (id)retain {
343     return [WebUndefined undefined];
344 }
345
346 - (void)release {
347 }
348
349 - (unsigned)retainCount {
350     return 0xFFFFFFFF;
351 }
352
353 - (id)autorelease {
354     return [WebUndefined undefined];
355 }
356
357 - (void)dealloc {
358 }
359
360 - (id)copy {
361     return [WebUndefined undefined];
362 }
363
364 - (id)replacementObjectForPortCoder:(NSPortCoder *)encoder {
365     return [WebUndefined undefined];
366 }
367
368 @end