blob: c6e50b8c724b7fdd5fa088dd2b093e78c3c8d745 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 IBM Corporation and others All rights reserved. This
* program and the accompanying materials are made available under the terms of
* the Eclipse Public License v1.0 which accompanies this distribution, and is
* available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors: IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.e4.languages.javascript.debug.rhino;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeSet;
import org.eclipse.e4.languages.javascript.debug.connect.JSONConstants;
import org.eclipse.e4.languages.javascript.debug.connect.JSONUtil;
import org.mozilla.javascript.debug.DebuggableScript;
/**
* Rhino script implementation
*
* @since 1.0
*/
public class ScriptImpl {
private static final String TOP_NAME = ""; //$NON-NLS-1$
/**
* struct for a script handle
*/
static class ScriptRecord {
String name = null;
int firstLine = 1;
}
private final Long scriptId;
private final String location;
private final Map sourceProperties;
private final String source;
private final Boolean generated;
private final Collection functionNames = new HashSet();
private final Collection lineNumbers = new HashSet();
private final Map scriptRecords = new HashMap();
private Collection breakpoints = new ArrayList();
/**
* Constructor
*
* @param scriptId
* @param debuggableScript
* @param source
*/
public ScriptImpl(Long scriptId, DebuggableScript debuggableScript, String source) {
this.scriptId = scriptId;
String sourceName = debuggableScript.getSourceName();
this.sourceProperties = parseSourceProperties(sourceName);
this.location = (sourceProperties == null) ? sourceName : (String) sourceProperties.get(JSONConstants.NAME);
this.generated = Boolean.valueOf(debuggableScript.isGeneratedScript());
this.source = source;
int[] scriptLineNumbers = debuggableScript.getLineNumbers();
for (int i = 0; i < scriptLineNumbers.length; i++) {
lineNumbers.add(new Integer(scriptLineNumbers[i] + 1));
}
scriptRecords.put(debuggableScript, new ScriptRecord());
expandFunctions(TOP_NAME, debuggableScript);
}
private static Map parseSourceProperties(String sourceName) {
if (sourceName != null && sourceName.charAt(0) == '{') {
try {
Object json = JSONUtil.read(sourceName);
if (json instanceof Map) {
return (Map) json;
}
} catch (RuntimeException e) {
// ignore
}
}
return null;
}
/**
* Expands the function name
*
* @param prefix
* @param debuggableScript
*/
private void expandFunctions(String prefix, DebuggableScript debuggableScript) {
int functionCount = debuggableScript.getFunctionCount();
for (int i = 0; i < functionCount; i++) {
DebuggableScript functionScript = debuggableScript.getFunction(i);
ScriptRecord record = new ScriptRecord();
scriptRecords.put(functionScript, record);
String functionName = functionScript.getFunctionName();
if ((functionName == null) || functionName.equals(TOP_NAME)) {
functionName = "%" + i; //$NON-NLS-1$
}
record.name = prefix + functionName;
functionNames.add(record.name);
int[] scriptLineNumbers = functionScript.getLineNumbers();
if (scriptLineNumbers != null && scriptLineNumbers.length != 0) {
record.firstLine = scriptLineNumbers[0] + 1;
for (int j = 0; j < scriptLineNumbers.length; j++) {
int currentLine = scriptLineNumbers[j] + 1;
if (currentLine < record.firstLine) {
record.firstLine = currentLine;
}
lineNumbers.add(new Integer(currentLine));
}
}
expandFunctions(record.name + ".", functionScript); //$NON-NLS-1$
}
}
/**
* @return a new JSON map
*/
public Object toJSON() {
HashMap result = new HashMap();
result.put(JSONConstants.SCRIPT_ID, scriptId);
result.put(JSONConstants.LOCATION, location);
result.put(JSONConstants.PROPERTIES, sourceProperties);
result.put(JSONConstants.SOURCE, source);
result.put(JSONConstants.GENERATED, generated);
result.put(JSONConstants.LINES, new TreeSet(lineNumbers));
result.put(JSONConstants.FUNCTIONS, new TreeSet(functionNames));
return result;
}
/**
* @return the id for this script object
*/
public Long getId() {
return scriptId;
}
/**
* Returns the complete collection of breakpoints that match the given attributes or an empty collection, never <code>null</code>
*
* @param functionName
* @param lineNumber
* @param frame
* @return all breakpoints that match the given attributes or an empty collection
*/
public synchronized Collection getBreakpoints(String functionName, Integer lineNumber, DebugFrameImpl frame) {
ArrayList result = new ArrayList();
for (Iterator iterator = breakpoints.iterator(); iterator.hasNext();) {
BreakpointImpl breakpoint = (BreakpointImpl) iterator.next();
if (breakpoint.matches(functionName, lineNumber, frame)) {
result.add(breakpoint.getId());
}
}
return result;
}
/**
* Returns if the line number or the function is valid wrt this script
*
* @param lineNumber
* @param functionName
* @return true if the line number or function name is valid wrt this script
*/
public boolean isValid(Integer lineNumber, String functionName) {
if (lineNumber != null) {
return lineNumbers.contains(lineNumber);
}
if (functionName != null) {
return functionNames.contains(functionName);
}
return functionName == null;
}
/**
* Adds a breakpoint to this script
*
* @param breakpoint
*/
public synchronized void addBreakpoint(BreakpointImpl breakpoint) {
breakpoints.add(breakpoint);
}
/**
* Removes a breakpoint from this script
*
* @param breakpoint
*/
public synchronized void removeBreakpoint(BreakpointImpl breakpoint) {
breakpoints.remove(breakpoint);
}
/**
* @return the string location of this script
*/
public String getLocation() {
return location;
}
/**
* Returns the {@link ScriptRecord} for the debuggable script or <code>null</code>
*
* @param debuggableScript
* @return the {@link ScriptRecord} for the given {@link DebuggableScript} or <code>null</code>
*/
public ScriptRecord getRecord(DebuggableScript debuggableScript) {
return (ScriptRecord) scriptRecords.get(debuggableScript);
}
}