Remove WebCoreScriptDebugger
[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 "WebCoreScriptDebuggerImp.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 #import <WebCore/runtime_root.h>
45
46 using namespace KJS;
47 using namespace WebCore;
48
49 // FIXME: these error strings should be public for future use by WebScriptObject and in WebScriptObject.h
50 NSString * const WebScriptErrorDomain = @"WebScriptErrorDomain";
51 NSString * const WebScriptErrorDescriptionKey = @"WebScriptErrorDescription";
52 NSString * const WebScriptErrorLineNumberKey = @"WebScriptErrorLineNumber";
53
54 @interface WebScriptCallFrame (WebScriptDebugDelegateInternal)
55
56 - (WebScriptCallFrame *)_initWithGlobalObject:(WebScriptObject *)globalObj caller:(WebScriptCallFrame *)caller state:(ExecState *)state;
57 - (id)_convertValueToObjcValue:(JSValue *)value;
58
59 @end
60
61 @implementation WebScriptDebugger
62
63 - (WebScriptDebugger *)initWithWebFrame:(WebFrame *)webFrame
64 {
65     if ((self = [super init])) {
66         _webFrame = webFrame;
67         _debugger = new WebCoreScriptDebuggerImp(self, [[self globalObject] _rootObject]->globalObject());
68     }
69     return self;
70 }
71
72 - (void)dealloc
73 {
74     delete _debugger;
75     [_current release];
76     [super dealloc];
77 }
78
79 - (WebScriptObject *)globalObject
80 {
81     return core(_webFrame)->windowScriptObject();
82 }
83
84 - (WebScriptCallFrame *)enterFrame:(ExecState*)state;
85 {
86     _current = [[WebScriptCallFrame alloc] _initWithGlobalObject:[self globalObject] caller:_current state:state];
87     return _current;
88 }
89
90 - (WebScriptCallFrame *)leaveFrame;
91 {
92     WebScriptCallFrame *caller = [[_current caller] retain];
93     [_current release];
94     return _current = caller;
95 }
96
97 - (void)parsedSource:(NSString *)source fromURL:(NSURL *)url sourceId:(int)sid startLine:(int)startLine errorLine:(int)errorLine errorMessage:(NSString *)errorMessage
98 {
99     WebView *webView = [_webFrame webView];
100     if (errorLine == -1) {
101         [[webView _scriptDebugDelegateForwarder] webView:webView didParseSource:source baseLineNumber:startLine fromURL:url sourceId:sid forWebFrame:_webFrame];
102         [[webView _scriptDebugDelegateForwarder] webView:webView didParseSource:source fromURL:[url absoluteString] sourceId:sid forWebFrame:_webFrame]; // deprecated delegate method
103         if ([WebScriptDebugServer listenerCount])
104             [[WebScriptDebugServer sharedScriptDebugServer] webView:webView didParseSource:source baseLineNumber:startLine fromURL:url sourceId:sid forWebFrame:_webFrame];
105     } else {
106         NSDictionary *info = [[NSDictionary alloc] initWithObjectsAndKeys:errorMessage, WebScriptErrorDescriptionKey, [NSNumber numberWithUnsignedInt:errorLine], WebScriptErrorLineNumberKey, nil];
107         NSError *error = [[NSError alloc] initWithDomain:WebScriptErrorDomain code:WebScriptGeneralErrorCode userInfo:info];
108         [[webView _scriptDebugDelegateForwarder] webView:webView failedToParseSource:source baseLineNumber:startLine fromURL:url withError:error forWebFrame:_webFrame];
109         if ([WebScriptDebugServer listenerCount])
110             [[WebScriptDebugServer sharedScriptDebugServer] webView:webView failedToParseSource:source baseLineNumber:startLine fromURL:url withError:error forWebFrame:_webFrame];
111         [error release];
112         [info release];
113     }
114 }
115
116 - (void)enteredFrame:(WebScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno
117 {
118     WebView *webView = [_webFrame webView];
119     [[webView _scriptDebugDelegateForwarder] webView:webView didEnterCallFrame:frame sourceId:sid line:lineno forWebFrame:_webFrame];
120     if ([WebScriptDebugServer listenerCount])
121         [[WebScriptDebugServer sharedScriptDebugServer] webView:webView didEnterCallFrame:frame sourceId:sid line:lineno forWebFrame:_webFrame];
122 }
123
124 - (void)hitStatement:(WebScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno
125 {
126     WebView *webView = [_webFrame webView];
127     [[webView _scriptDebugDelegateForwarder] webView:webView willExecuteStatement:frame sourceId:sid line:lineno forWebFrame:_webFrame];
128     if ([WebScriptDebugServer listenerCount])
129         [[WebScriptDebugServer sharedScriptDebugServer] webView:webView willExecuteStatement:frame sourceId:sid line:lineno forWebFrame:_webFrame];
130 }
131
132 - (void)leavingFrame:(WebScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno
133 {
134     WebView *webView = [_webFrame webView];
135     [[webView _scriptDebugDelegateForwarder] webView:webView willLeaveCallFrame:frame sourceId:sid line:lineno forWebFrame:_webFrame];
136     if ([WebScriptDebugServer listenerCount])
137         [[WebScriptDebugServer sharedScriptDebugServer] webView:webView willLeaveCallFrame:frame sourceId:sid line:lineno forWebFrame:_webFrame];
138 }
139
140 - (void)exceptionRaised:(WebScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno
141 {
142     WebView *webView = [_webFrame webView];
143     [[webView _scriptDebugDelegateForwarder] webView:webView exceptionWasRaised:frame sourceId:sid line:lineno forWebFrame:_webFrame];
144     if ([WebScriptDebugServer listenerCount])
145         [[WebScriptDebugServer sharedScriptDebugServer] webView:webView exceptionWasRaised:frame sourceId:sid line:lineno forWebFrame:_webFrame];
146 }
147
148 @end
149
150 @interface WebScriptCallFramePrivate : NSObject {
151 @public
152     WebScriptObject        *globalObject;   // the global object's proxy (not retained)
153     WebScriptCallFrame     *caller;         // previous stack frame
154     KJS::ExecState         *state;
155 }
156 @end
157
158 @implementation WebScriptCallFramePrivate
159 - (void)dealloc
160 {
161     [caller release];
162     [super dealloc];
163 }
164 @end
165
166 // WebScriptCallFrame
167 //
168 // One of these is created to represent each stack frame.  Additionally, there is a "global"
169 // frame to represent the outermost scope.  This global frame is always the last frame in
170 // the chain of callers.
171 //
172 // The delegate can assign a "wrapper" to each frame object so it can relay calls through its
173 // own exported interface.  This class is private to WebCore (and the delegate).
174
175 @implementation WebScriptCallFrame (WebScriptDebugDelegateInternal)
176
177 - (WebScriptCallFrame *)_initWithGlobalObject:(WebScriptObject *)globalObj caller:(WebScriptCallFrame *)caller state:(ExecState *)state
178 {
179     if ((self = [super init])) {
180         _private = [[WebScriptCallFramePrivate alloc] init];
181         _private->globalObject = globalObj;
182         _private->caller = caller; // (already retained)
183         _private->state = state;
184     }
185     return self;
186 }
187
188 - (id)_convertValueToObjcValue:(JSValue *)value
189 {
190     if (!value)
191         return nil;
192
193     WebScriptObject *globalObject = _private->globalObject;
194     if (value == [globalObject _imp])
195         return globalObject;
196
197     Bindings::RootObject* root1 = [globalObject _originRootObject];
198     if (!root1)
199         return nil;
200
201     Bindings::RootObject* root2 = [globalObject _rootObject];
202     if (!root2)
203         return nil;
204
205     return [WebScriptObject _convertValueToObjcValue:value originRootObject:root1 rootObject:root2];
206 }
207
208 @end
209
210
211
212 @implementation WebScriptCallFrame
213
214 - (void) dealloc
215 {
216     [_userInfo release];
217     [_private release];
218     [super dealloc];
219 }
220
221 - (void)setUserInfo:(id)userInfo
222 {
223     if (userInfo != _userInfo) {
224         [_userInfo release];
225         _userInfo = [userInfo retain];
226     }
227 }
228
229 - (id)userInfo
230 {
231     return _userInfo;
232 }
233
234 - (WebScriptCallFrame *)caller
235 {
236     return _private->caller;
237 }
238
239 // Returns an array of scope objects (most local first).
240 // The properties of each scope object are the variables for that scope.
241 // Note that the last entry in the array will _always_ be the global object (windowScriptObject),
242 // whose properties are the global variables.
243
244 - (NSArray *)scopeChain
245 {
246     ExecState* state = _private->state;
247     if (!state->scopeNode())  // global frame
248         return [NSArray arrayWithObject:_private->globalObject];
249
250     ScopeChain      chain  = state->scopeChain();
251     NSMutableArray *scopes = [[NSMutableArray alloc] init];
252
253     while (!chain.isEmpty()) {
254         [scopes addObject:[self _convertValueToObjcValue:chain.top()]];
255         chain.pop();
256     }
257
258     NSArray *result = [NSArray arrayWithArray:scopes];
259     [scopes release];
260     return result;
261 }
262
263 // Returns the name of the function for this frame, if available.
264 // Returns nil for anonymous functions and for the global frame.
265
266 - (NSString *)functionName
267 {
268     ExecState* state = _private->state;
269     if (!state->scopeNode())
270         return nil;
271
272     FunctionImp* func = state->function();
273     if (!func)
274         return nil;
275
276     Identifier fn = func->functionName();
277     return toNSString(fn.ustring());
278 }
279
280 // Returns the pending exception for this frame (nil if none).
281
282 - (id)exception
283 {
284     ExecState* state = _private->state;
285     if (!state->hadException())
286         return nil;
287     return [self _convertValueToObjcValue:state->exception()];
288 }
289
290 // Evaluate some JavaScript code in the context of this frame.
291 // The code is evaluated as if by "eval", and the result is returned.
292 // If there is an (uncaught) exception, it is returned as though _it_ were the result.
293 // Calling this method on the global frame is not quite the same as calling the WebScriptObject
294 // method of the same name, due to the treatment of exceptions.
295
296 // FIXME: If "script" contains var declarations, the machinery to handle local variables
297 // efficiently in JavaScriptCore will not work properly. This could lead to crashes or
298 // incorrect variable values. So this is not appropriate for evaluating arbitrary script.
299 - (id)evaluateWebScript:(NSString *)script
300 {
301     JSLock lock;
302
303     UString code = String(script);
304
305     ExecState* state = _private->state;
306     JSGlobalObject* globalObject = state->dynamicGlobalObject();
307
308     // find "eval"
309     JSObject* eval = NULL;
310     if (state->scopeNode()) {  // "eval" won't work without context (i.e. at global scope)
311         JSValue* v = globalObject->get(state, "eval");
312         if (v->isObject() && static_cast<JSObject*>(v)->implementsCall())
313             eval = static_cast<JSObject*>(v);
314         else
315             // no "eval" - fallback operates on global exec state
316             state = globalObject->globalExec();
317     }
318
319     JSValue* savedException = state->exception();
320     state->clearException();
321
322     // evaluate
323     JSValue* result;
324     if (eval) {
325         List args;
326         args.append(jsString(code));
327         result = eval->call(state, 0, args);
328     } else
329         // no "eval", or no context (i.e. global scope) - use global fallback
330         result = Interpreter::evaluate(state, UString(), 0, code.data(), code.size(), globalObject).value();
331
332     if (state->hadException())
333         result = state->exception();    // (may be redundant depending on which eval path was used)
334     state->setException(savedException);
335
336     return [self _convertValueToObjcValue:result];
337 }
338
339 @end