blob: 4ab2897047e2ee25de6574983785598899fd51d7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2018 S.Boyko and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* S.Boyko - initial API and implementation
*******************************************************************************/
package org.eclipse.m2m.internal.tests.qvt.oml.debugger;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.eclipse.debug.core.DebugEvent;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* Responsible for parsing a script file (XML) into commands and for storing
* those commands
*/
class Script {
public Script(String fileName, MarkedTransformation markedTrans) throws Exception {
myCommandList = new ArrayList<Command>();
myMarkedTrans = markedTrans;
myModule = fileName;
parseFile(fileName);
reset();
}
private void parseFile(String fileName) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(true);
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setErrorHandler(new ErrorHandler() {
public void error(SAXParseException arg0) throws SAXException {
System.err.println(arg0);
}
public void fatalError(SAXParseException arg0) throws SAXException {
System.err.println(arg0);
}
public void warning(SAXParseException arg0) throws SAXException {
System.err.println(arg0);
}
});
Document document = builder.parse(fileName);
NodeList commands = document.getDocumentElement().getChildNodes();
int prevCode = INVALID_CODE; // no previous command
for (int i = 0; i < commands.getLength(); i++) {
Node node = commands.item(i);
if (node.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
// Retrieve code
String command = node.getNodeName();
int code = commandToCode(command);
if (code == BREAKPOINT_CODE) {
throw new ScriptException(MessageFormat.format(INVALID_COMMAND_MESSAGE, new Object[]{command}));
}
// Retrieve line number
String markerName = node.getAttributes().getNamedItem(LINE).getNodeValue();
int lineNumber = -1;
if (Character.isDigit(markerName.charAt(0))) {
lineNumber = Integer.valueOf(markerName).intValue();
}
else {
MarkedTransformation.LineMarker myRec = myMarkedTrans.getLineMarker(markerName);
if (myRec == null) {
throw new ScriptException(MessageFormat.format(UNKNOWN_NAME_MESSAGE, new Object[]{markerName, myModule}));
}
lineNumber = myRec.lineNumber;
}
// Retrieve cause
Node causeNode = node.getAttributes().getNamedItem(CAUSE);
int cause = commandToCode(causeNode.getNodeValue());
if (cause == NONE_CODE) {
// Stop might is caused by result of the previous command
cause = prevCode;
if (cause == INVALID_CODE) {
throw new Exception(MessageFormat.format(INVALID_CAUSE_MESSAGE, new Object[]{command, markerName}));
}
}
myCommandList.add(new Command(node.toString(), code, lineNumber, cause));
prevCode = code;
}
}
/**
* Converts given command into a code
* @param command - a string command
* @return command's code, 0 for unknown command
*/
private int commandToCode(String command) throws ScriptException {
if (command.equals(RESUME_STRING)) {
return RESUME_CODE;
}
else if (command.equals(STEP_OVER_STRING)) {
return STEP_OVER_CODE;
}
else if (command.equals(STEP_INTO_STRING)) {
return STEP_INTO_CODE;
}
else if (command.equals(STEP_RETURN_STRING)) {
return STEP_RETURN_CODE;
}
else if (command.equals(BREAKPOINT_STRING)) {
return BREAKPOINT_CODE;
}
else if (command.equals(NONE_STRING)) {
return NONE_CODE;
}
else {
throw new ScriptException(MessageFormat.format(UNKNOWN_COMMAND_MESSAGE, new Object[]{command}));
}
}
/**
* Sets internal iterator to the beginning of the command list
*/
public void reset() {
myIterator = myCommandList.iterator();
}
/**
* @return <code>true</code> if there are commands left in the list
*/
public boolean hasNextCommand() {
return myIterator.hasNext();
}
/**
* @return next <code>Command</code>
*/
public Command nextCommand() {
return myIterator.next();
}
/**
* Represents a script command command
*/
public class Command {
public Command(String command, int code, int lineNumber, int cause) {
this.command = command;
this.code = code;
this.lineNumber = lineNumber;
this.cause = cause;
}
/**
* @return DebugEvent.getDetail() representation of cause field
*/
public int getEventDetail() {
switch (cause) {
case STEP_OVER_CODE:
return DebugEvent.STEP_OVER;
case STEP_INTO_CODE:
return DebugEvent.STEP_INTO;
case STEP_RETURN_CODE:
return DebugEvent.STEP_RETURN;
case BREAKPOINT_CODE:
return DebugEvent.BREAKPOINT;
default:
return DebugEvent.UNSPECIFIED;
}
}
public String toString() {
return command;
}
public final String command;
public final int code;
public final int lineNumber;
public final int cause;
}
public class ScriptException extends Exception {
public ScriptException(String s) {
super(s);
}
private static final long serialVersionUID = 380437041238179652L;
}
private final List<Command> myCommandList;
private Iterator<Command> myIterator;
private final MarkedTransformation myMarkedTrans;
private String myModule;
/* Code and Cause strings */
private static final String RESUME_STRING = "resume"; //$NON-NLS-1$
private static final String STEP_OVER_STRING = "stepOver"; //$NON-NLS-1$
private static final String STEP_INTO_STRING = "stepInto"; //$NON-NLS-1$
private static final String STEP_RETURN_STRING = "return"; //$NON-NLS-1$
private static final String BREAKPOINT_STRING = "breakpoint"; //$NON-NLS-1$
private static final String NONE_STRING = "none"; //$NON-NLS-1$
/* Code and Cause codes */
public static final int RESUME_CODE = 1;
public static final int STEP_OVER_CODE = 2;
public static final int STEP_INTO_CODE = 3;
public static final int STEP_RETURN_CODE = 4;
public static final int BREAKPOINT_CODE = 5;
public static final int NONE_CODE = 0;
public static final int INVALID_CODE = -1;
/* Attribute names */
private static final String LINE = "line"; //$NON-NLS-1$
private static final String CAUSE = "cause"; //$NON-NLS-1$
/* Error messages */
private static final String UNKNOWN_COMMAND_MESSAGE = "Unknown command: {0}"; //$NON-NLS-1$
private static final String UNKNOWN_NAME_MESSAGE = "Unknown marker name: {0} in {1}"; //$NON-NLS-1$
private static final String INVALID_CAUSE_MESSAGE = "Invalid cause: {0} line=\"{1}\""; //$NON-NLS-1$
private static final String INVALID_COMMAND_MESSAGE = "Invalid command: {0}"; //$NON-NLS-1$
}