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