blob: b49338c38cc56f5ee2d156f2173deee4257ba2d0 [file] [log] [blame]
/*
* Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
* Copyright (C) 2006, 2007 Vladimir Olexa (vladimir.olexa@gmail.com)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "config.h"
#import "DebuggerDocument.h"
#import "DebuggerClient.h"
#import "ServerConnection.h"
#import <JavaScriptCore/JSRetainPtr.h>
#import <JavaScriptCore/JSStringRefCF.h>
#import <JavaScriptCore/RetainPtr.h>
// Converting string types
NSString* NSStringCreateWithJSStringRef(JSStringRef jsString)
{
CFStringRef cfString = JSStringCopyCFString(kCFAllocatorDefault, jsString);
return (NSString *)cfString;
}
JSValueRef JSValueRefCreateWithNSString(JSContextRef context, NSString* nsString)
{
JSRetainPtr<JSStringRef> jsString(Adopt, JSStringCreateWithCFString((CFStringRef)nsString));
return JSValueMakeString(context, jsString.get());
}
@interface NSString (WebScriptStringExtras)
+ (NSString *)stringOrNilFromWebScriptResult:(id)scriptResult;
@end
@implementation NSString (WebScriptStringExtras)
+ (NSString *)stringOrNilFromWebScriptResult:(id)scriptResult
{
NSString *ret = nil;
if ([scriptResult isKindOfClass:NSClassFromString(@"WebScriptObject")])
ret = [scriptResult callWebScriptMethod:@"toString" withArguments:nil];
else if (scriptResult && ![scriptResult isKindOfClass:[NSString class]])
ret = [scriptResult description];
else if (scriptResult)
ret = scriptResult;
return ret;
}
@end
@interface WebScriptObject (WebScriptObjectExtras)
+ (NSArray *)webScriptAttributeKeys:(WebScriptObject *)object;
@end
@implementation WebScriptObject (WebScriptObjectExtras)
+ (NSArray *)webScriptAttributeKeys:(WebScriptObject *)object;
{
WebScriptObject *enumerateAttributes = [object evaluateWebScript:@"(function () { var result = new Array(); for (var x in this) { result.push(x); } return result; })"];
NSMutableArray *result = [[NSMutableArray alloc] init];
WebScriptObject *variables = [enumerateAttributes callWebScriptMethod:@"call" withArguments:[NSArray arrayWithObject:object]];
unsigned length = [[variables valueForKey:@"length"] intValue];
for (unsigned i = 0; i < length; i++) {
NSString *key = [variables webScriptValueAtIndex:i];
[result addObject:key];
}
[result sortUsingSelector:@selector(compare:)];
return [result autorelease];
}
@end
// DebuggerDocument platform specific implementations
void DebuggerDocument::platformPause()
{
[m_server.get() pause];
}
void DebuggerDocument::platformResume()
{
[m_server.get() resume];
}
void DebuggerDocument::platformStepInto()
{
[m_server.get() stepInto];
}
JSValueRef DebuggerDocument::platformEvaluateScript(JSContextRef context, JSStringRef script, int callFrame)
{
WebScriptCallFrame *cframe = [m_server.get() currentFrame];
for (unsigned count = 0; count < callFrame; count++)
cframe = [cframe caller];
if (!cframe)
return JSValueMakeUndefined(context);
RetainPtr<NSString> scriptNS(AdoptNS, NSStringCreateWithJSStringRef(script));
id value = [cframe evaluateWebScript:scriptNS.get()];
NSString *result = [NSString stringOrNilFromWebScriptResult:value];
if (!result)
return JSValueMakeNull(context);
return JSValueRefCreateWithNSString(context, result);
}
void DebuggerDocument::getPlatformCurrentFunctionStack(JSContextRef context, Vector<JSValueRef>& currentStack)
{
for (WebScriptCallFrame *frame = [m_server.get() currentFrame]; frame;) {
CFStringRef function;
if ([frame functionName])
function = (CFStringRef)[frame functionName];
else if ([frame caller])
function = CFSTR("(anonymous function)");
else
function = CFSTR("(global scope)");
frame = [frame caller];
currentStack.append(JSValueRefCreateWithNSString(context, (NSString *)function));
}
}
void DebuggerDocument::getPlatformLocalScopeVariableNamesForCallFrame(JSContextRef context, int callFrame, Vector<JSValueRef>& variableNames)
{
WebScriptCallFrame *cframe = [m_server.get() currentFrame];
for (unsigned count = 0; count < callFrame; count++)
cframe = [cframe caller];
if (!cframe)
return;
if (![[cframe scopeChain] count])
return;
WebScriptObject *scope = [[cframe scopeChain] objectAtIndex:0]; // local is always first
NSArray *localScopeVariableNames = [WebScriptObject webScriptAttributeKeys:scope];
for (int i = 0; i < [localScopeVariableNames count]; ++i) {
variableNames.append(JSValueRefCreateWithNSString(context, [localScopeVariableNames objectAtIndex:i]));
}
}
JSValueRef DebuggerDocument::platformValueForScopeVariableNamed(JSContextRef context, JSStringRef key, int callFrame)
{
WebScriptCallFrame *cframe = [m_server.get() currentFrame];
for (unsigned count = 0; count < callFrame; count++)
cframe = [cframe caller];
if (!cframe)
return JSValueMakeUndefined(context);
unsigned scopeCount = [[cframe scopeChain] count];
if (!scopeCount)
return JSValueMakeUndefined(context);
NSString *resultString = nil;
for (unsigned i = 0; i < scopeCount && resultString == nil; i++) {
WebScriptObject *scope = [[cframe scopeChain] objectAtIndex:i];
id value = nil;
@try {
RetainPtr<NSString> keyNS(AdoptNS, NSStringCreateWithJSStringRef(key));
value = [scope valueForKey:keyNS.get()];
} @catch(NSException* localException) { // The value wasn't found.
}
resultString = [NSString stringOrNilFromWebScriptResult:value];
}
if (!resultString)
return JSValueMakeUndefined(context);
return JSValueRefCreateWithNSString(context, resultString);
}
void DebuggerDocument::platformLog(JSStringRef msg)
{
RetainPtr<NSString> msgNS(AdoptNS, NSStringCreateWithJSStringRef(msg));
NSLog(@"%@", msgNS.get());
}