Move -_convertValueToObjcValue to WebScriptCallFrame
[WebKit-https.git] / WebKit / mac / WebView / WebScriptDebugDelegate.mm
1 /*
2  * Copyright (C) 2005 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #import "WebScriptDebugDelegatePrivate.h"
30
31 #import "WebCoreScriptDebugger.h"
32 #import "WebDataSource.h"
33 #import "WebDataSourceInternal.h"
34 #import "WebFrameBridge.h"
35 #import "WebFrameInternal.h"
36 #import "WebScriptDebugServerPrivate.h"
37 #import "WebViewInternal.h"
38 #import <JavaScriptCore/ExecState.h>
39 #import <JavaScriptCore/JSGlobalObject.h>
40 #import <JavaScriptCore/function.h>
41 #import <JavaScriptCore/interpreter.h>
42 #import <WebCore/Frame.h>
43 #import <WebCore/WebScriptObjectPrivate.h>
44
45 using namespace KJS;
46 using namespace WebCore;
47
48 // FIXME: these error strings should be public for future use by WebScriptObject and in WebScriptObject.h
49 NSString * const WebScriptErrorDomain = @"WebScriptErrorDomain";
50 NSString * const WebScriptErrorDescriptionKey = @"WebScriptErrorDescription";
51 NSString * const WebScriptErrorLineNumberKey = @"WebScriptErrorLineNumber";
52
53 @interface WebScriptCallFrame (WebScriptDebugDelegateInternal)
54
55 - (WebScriptCallFrame *)_initWithFrame:(WebCoreScriptCallFrame *)frame;
56 - (id)_convertValueToObjcValue:(JSValue *)value;
57
58 @end
59
60 @implementation WebScriptDebugger
61
62 - (WebScriptDebugger *)initWithWebFrame:(WebFrame *)webFrame
63 {
64     if ((self = [super init])) {
65         _webFrame = webFrame;
66         _debugger = [[WebCoreScriptDebugger alloc] initWithDelegate:self];
67     }
68     return self;
69 }
70
71 - (void)dealloc
72 {
73     [_debugger release];
74     [super dealloc];
75 }
76
77 - (WebScriptObject *)globalObject
78 {
79     return core(_webFrame)->windowScriptObject();
80 }
81
82 - (id)newWrapperForFrame:(WebCoreScriptCallFrame *)frame
83 {
84     return [[WebScriptCallFrame alloc] _initWithFrame:frame];
85 }
86
87 - (void)parsedSource:(NSString *)source fromURL:(NSURL *)url sourceId:(int)sid startLine:(int)startLine errorLine:(int)errorLine errorMessage:(NSString *)errorMessage
88 {
89     WebView *webView = [_webFrame webView];
90     if (errorLine == -1) {
91         [[webView _scriptDebugDelegateForwarder] webView:webView didParseSource:source baseLineNumber:startLine fromURL:url sourceId:sid forWebFrame:_webFrame];
92         [[webView _scriptDebugDelegateForwarder] webView:webView didParseSource:source fromURL:[url absoluteString] sourceId:sid forWebFrame:_webFrame]; // deprecated delegate method
93         if ([WebScriptDebugServer listenerCount])
94             [[WebScriptDebugServer sharedScriptDebugServer] webView:webView didParseSource:source baseLineNumber:startLine fromURL:url sourceId:sid forWebFrame:_webFrame];
95     } else {
96         NSDictionary *info = [[NSDictionary alloc] initWithObjectsAndKeys:errorMessage, WebScriptErrorDescriptionKey, [NSNumber numberWithUnsignedInt:errorLine], WebScriptErrorLineNumberKey, nil];
97         NSError *error = [[NSError alloc] initWithDomain:WebScriptErrorDomain code:WebScriptGeneralErrorCode userInfo:info];
98         [[webView _scriptDebugDelegateForwarder] webView:webView failedToParseSource:source baseLineNumber:startLine fromURL:url withError:error forWebFrame:_webFrame];
99         if ([WebScriptDebugServer listenerCount])
100             [[WebScriptDebugServer sharedScriptDebugServer] webView:webView failedToParseSource:source baseLineNumber:startLine fromURL:url withError:error forWebFrame:_webFrame];
101         [error release];
102         [info release];
103     }
104 }
105
106 - (void)enteredFrame:(WebCoreScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno
107 {
108     WebView *webView = [_webFrame webView];
109     [[webView _scriptDebugDelegateForwarder] webView:webView didEnterCallFrame:[frame wrapper] sourceId:sid line:lineno forWebFrame:_webFrame];
110     if ([WebScriptDebugServer listenerCount])
111         [[WebScriptDebugServer sharedScriptDebugServer] webView:webView didEnterCallFrame:[frame wrapper] sourceId:sid line:lineno forWebFrame:_webFrame];
112 }
113
114 - (void)hitStatement:(WebCoreScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno
115 {
116     WebView *webView = [_webFrame webView];
117     [[webView _scriptDebugDelegateForwarder] webView:webView willExecuteStatement:[frame wrapper] sourceId:sid line:lineno forWebFrame:_webFrame];
118     if ([WebScriptDebugServer listenerCount])
119         [[WebScriptDebugServer sharedScriptDebugServer] webView:webView willExecuteStatement:[frame wrapper] sourceId:sid line:lineno forWebFrame:_webFrame];
120 }
121
122 - (void)leavingFrame:(WebCoreScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno
123 {
124     WebView *webView = [_webFrame webView];
125     [[webView _scriptDebugDelegateForwarder] webView:webView willLeaveCallFrame:[frame wrapper] sourceId:sid line:lineno forWebFrame:_webFrame];
126     if ([WebScriptDebugServer listenerCount])
127         [[WebScriptDebugServer sharedScriptDebugServer] webView:webView willLeaveCallFrame:[frame wrapper] sourceId:sid line:lineno forWebFrame:_webFrame];
128 }
129
130 - (void)exceptionRaised:(WebCoreScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno
131 {
132     WebView *webView = [_webFrame webView];
133     [[webView _scriptDebugDelegateForwarder] webView:webView exceptionWasRaised:[frame wrapper] sourceId:sid line:lineno forWebFrame:_webFrame];
134     if ([WebScriptDebugServer listenerCount])
135         [[WebScriptDebugServer sharedScriptDebugServer] webView:webView exceptionWasRaised:[frame wrapper] sourceId:sid line:lineno forWebFrame:_webFrame];
136 }
137
138 @end
139
140
141
142 @implementation WebScriptCallFrame (WebScriptDebugDelegateInternal)
143
144 - (WebScriptCallFrame *)_initWithFrame:(WebCoreScriptCallFrame *)frame
145 {
146     if ((self = [super init])) {
147         _private = frame;
148     }
149     return self;
150 }
151
152 - (id)_convertValueToObjcValue:(JSValue *)value
153 {
154     if (!value)
155         return nil;
156
157     WebScriptObject *globalObject = [_private globalObject];
158     if (value == [globalObject _imp])
159         return globalObject;
160
161     Bindings::RootObject* root1 = [globalObject _originRootObject];
162     if (!root1)
163         return nil;
164
165     Bindings::RootObject* root2 = [globalObject _rootObject];
166     if (!root2)
167         return nil;
168
169     return [WebScriptObject _convertValueToObjcValue:value originRootObject:root1 rootObject:root2];
170 }
171
172 @end
173
174
175
176 @implementation WebScriptCallFrame
177
178 - (void) dealloc
179 {
180     [_userInfo release];
181     [super dealloc];
182 }
183
184 - (void)setUserInfo:(id)userInfo
185 {
186     if (userInfo != _userInfo) {
187         [_userInfo release];
188         _userInfo = [userInfo retain];
189     }
190 }
191
192 - (id)userInfo
193 {
194     return _userInfo;
195 }
196
197 - (WebScriptCallFrame *)caller
198 {
199     return [[_private caller] wrapper];
200 }
201
202 // Returns an array of scope objects (most local first).
203 // The properties of each scope object are the variables for that scope.
204 // Note that the last entry in the array will _always_ be the global object (windowScriptObject),
205 // whose properties are the global variables.
206
207 - (NSArray *)scopeChain
208 {
209     ExecState* state = [_private state];
210     if (!state->scopeNode())  // global frame
211         return [NSArray arrayWithObject:[_private globalObject]];
212
213     ScopeChain      chain  = state->scopeChain();
214     NSMutableArray *scopes = [[NSMutableArray alloc] init];
215
216     while (!chain.isEmpty()) {
217         [scopes addObject:[self _convertValueToObjcValue:chain.top()]];
218         chain.pop();
219     }
220
221     NSArray *result = [NSArray arrayWithArray:scopes];
222     [scopes release];
223     return result;
224 }
225
226 // Returns the name of the function for this frame, if available.
227 // Returns nil for anonymous functions and for the global frame.
228
229 - (NSString *)functionName
230 {
231     ExecState* state = [_private state];
232     if (!state->scopeNode())
233         return nil;
234
235     FunctionImp* func = state->function();
236     if (!func)
237         return nil;
238
239     Identifier fn = func->functionName();
240     return toNSString(fn.ustring());
241 }
242
243 // Returns the pending exception for this frame (nil if none).
244
245 - (id)exception
246 {
247     ExecState* state = [_private state];
248     if (!state->hadException())
249         return nil;
250     return [self _convertValueToObjcValue:state->exception()];
251 }
252
253 // Evaluate some JavaScript code in the context of this frame.
254 // The code is evaluated as if by "eval", and the result is returned.
255 // If there is an (uncaught) exception, it is returned as though _it_ were the result.
256 // Calling this method on the global frame is not quite the same as calling the WebScriptObject
257 // method of the same name, due to the treatment of exceptions.
258
259 // FIXME: If "script" contains var declarations, the machinery to handle local variables
260 // efficiently in JavaScriptCore will not work properly. This could lead to crashes or
261 // incorrect variable values. So this is not appropriate for evaluating arbitrary script.
262 - (id)evaluateWebScript:(NSString *)script
263 {
264     JSLock lock;
265
266     UString code = String(script);
267
268     ExecState* state = [_private state];
269     JSGlobalObject* globalObject = state->dynamicGlobalObject();
270
271     // find "eval"
272     JSObject* eval = NULL;
273     if (state->scopeNode()) {  // "eval" won't work without context (i.e. at global scope)
274         JSValue* v = globalObject->get(state, "eval");
275         if (v->isObject() && static_cast<JSObject*>(v)->implementsCall())
276             eval = static_cast<JSObject*>(v);
277         else
278             // no "eval" - fallback operates on global exec state
279             state = globalObject->globalExec();
280     }
281
282     JSValue* savedException = state->exception();
283     state->clearException();
284
285     // evaluate
286     JSValue* result;
287     if (eval) {
288         List args;
289         args.append(jsString(code));
290         result = eval->call(state, 0, args);
291     } else
292         // no "eval", or no context (i.e. global scope) - use global fallback
293         result = Interpreter::evaluate(state, UString(), 0, code.data(), code.size(), globalObject).value();
294
295     if (state->hadException())
296         result = state->exception();    // (may be redundant depending on which eval path was used)
297     state->setException(savedException);
298
299     return [self _convertValueToObjcValue:result];
300 }
301
302 @end