first step to bring debugging code to j2me

This commit is contained in:
Shu Lei
2007-10-12 01:36:28 +00:00
parent 6970b30c7a
commit 341a5588b0
35 changed files with 1294 additions and 220 deletions

View File

@@ -6,7 +6,5 @@
<classpathentry kind="src" path="src/test/res"/> <classpathentry kind="src" path="src/test/res"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3.8.1"/> <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3.8.1"/>
<classpathentry kind="lib" path="src/test/res/standard-tests.zip"/>
<classpathentry kind="lib" path="lib/commons-cli-1.1.jar"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>

View File

@@ -7,8 +7,7 @@
<target name="compile"> <target name="compile">
<mkdir dir="build/classes"/> <mkdir dir="build/classes"/>
<javac destdir="build/classes" encoding="utf-8" source="1.3" target="1.1" <javac destdir="build/classes" encoding="utf-8" source="1.3" target="1.1">
classpath="lib/commons-cli-1.1.jar" >
<src path="src/main/java"/> <src path="src/main/java"/>
<src path="src/addon/java"/> <src path="src/addon/java"/>
</javac> </javac>
@@ -46,7 +45,7 @@
<!-- Compile everything, but don't preverify (yet). --> <!-- Compile everything, but don't preverify (yet). -->
<mkdir dir="build/classes-j2me" /> <mkdir dir="build/classes-j2me" />
<wtkbuild destdir="build/classes-j2me" preverify="false" srcdir="build/src-j2me" /> <wtkbuild destdir="build/classes-j2me" preverify="false" srcdir="build/src-j2me" source="1.3" />
<!-- create the jar --> <!-- create the jar -->
<jar destfile="luaj-vm-j2me-${version}.jar" basedir="build/classes-j2me" /> <jar destfile="luaj-vm-j2me-${version}.jar" basedir="build/classes-j2me" />

Binary file not shown.

View File

@@ -21,11 +21,12 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
import java.io.Serializable; import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class DebugEvent implements Serializable { public class DebugEvent implements Serializable {
private static final long serialVersionUID = -6167781055176807311L;
protected DebugEventType type; protected DebugEventType type;
public DebugEvent(DebugEventType type) { public DebugEvent(DebugEventType type) {
@@ -45,5 +46,15 @@ public class DebugEvent implements Serializable {
*/ */
public String toString() { public String toString() {
return type.toString(); return type.toString();
} }
public static void serialize(DataOutputStream out, DebugEvent object)
throws IOException {
SerializationHelper.serialize(object.getType(), out);
}
public static DebugEvent deserialize(DataInputStream in) throws IOException {
DebugEventType type = (DebugEventType) SerializationHelper.deserialize(in);
return new DebugEvent(type);
}
} }

View File

@@ -21,13 +21,24 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class DebugEventBreakpoint extends DebugEvent { public class DebugEventBreakpoint extends DebugEvent {
private static final long serialVersionUID = -7573362646669094458L;
protected String source; protected String source;
protected int lineNumber; protected int lineNumber;
public DebugEventBreakpoint(String source, int lineNumber) { public DebugEventBreakpoint(String source, int lineNumber) {
super(DebugEventType.suspendedOnBreakpoint); super(DebugEventType.suspendedOnBreakpoint);
if (source == null) {
throw new IllegalArgumentException("argument source cannot be null");
}
if (lineNumber <= 0) {
throw new IllegalArgumentException("argument lineNumber must be positive integer");
}
this.source = source; this.source = source;
this.lineNumber = lineNumber; this.lineNumber = lineNumber;
} }
@@ -46,4 +57,17 @@ public class DebugEventBreakpoint extends DebugEvent {
public String toString() { public String toString() {
return super.toString() + " source:" + getSource() + " line:" + getLineNumber(); return super.toString() + " source:" + getSource() + " line:" + getLineNumber();
} }
public static void serialize(DataOutputStream out, DebugEventBreakpoint object)
throws IOException {
out.writeUTF(object.getSource());
out.writeInt(object.getLineNumber());
}
public static DebugEvent deserialize(DataInputStream in) throws IOException {
String source = in.readUTF();
int lineNo = in.readInt();
return new DebugEventBreakpoint(source, lineNo);
}
} }

View File

@@ -21,8 +21,11 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class DebugEventError extends DebugEvent { public class DebugEventError extends DebugEvent {
private static final long serialVersionUID = -7911842790951966147L;
protected String detail; protected String detail;
public DebugEventError(String detail) { public DebugEventError(String detail) {
@@ -40,4 +43,15 @@ public class DebugEventError extends DebugEvent {
public String toString() { public String toString() {
return super.toString() + " detail: " + getDetail(); return super.toString() + " detail: " + getDetail();
} }
public static void serialize(DataOutputStream out, DebugEventError object)
throws IOException {
//TODO implement
}
public static DebugEvent deserialize(DataInputStream in)
throws IOException {
//TODO implement
return null;
}
} }

View File

@@ -21,8 +21,12 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
import java.io.DataInputStream;
import java.io.IOException;
public class DebugEventType extends EnumType { public class DebugEventType extends EnumType {
public static DebugEventType started = new DebugEventType("started", 0); public static DebugEventType started = new DebugEventType("started", 0);
public static DebugEventType suspendedByClient = new DebugEventType("suspendedByClient", 1); public static DebugEventType suspendedByClient = new DebugEventType("suspendedByClient", 1);
public static DebugEventType suspendedOnBreakpoint = new DebugEventType("suspendedOnBreakpoint", 2); public static DebugEventType suspendedOnBreakpoint = new DebugEventType("suspendedOnBreakpoint", 2);
public static DebugEventType suspendedOnWatchpoint = new DebugEventType("suspendedOnWatchpoint", 3); public static DebugEventType suspendedOnWatchpoint = new DebugEventType("suspendedOnWatchpoint", 3);
@@ -34,7 +38,30 @@ public class DebugEventType extends EnumType {
public static DebugEventType error = new DebugEventType("error", 9); public static DebugEventType error = new DebugEventType("error", 9);
public static DebugEventType terminated = new DebugEventType("terminated", 10); public static DebugEventType terminated = new DebugEventType("terminated", 10);
protected static DebugEventType[] ENUMS = new DebugEventType[] {
started,
suspendedByClient,
suspendedOnBreakpoint,
suspendedOnWatchpoint,
suspendedOnStepping,
suspendedOnError,
resumedByClient,
resumedOnStepping,
resumedOnError,
error,
terminated
};
protected DebugEventType(String name, int ordinal) { protected DebugEventType(String name, int ordinal) {
super(name, ordinal); super(name, ordinal);
} }
public static DebugEventType deserialize(DataInputStream in)
throws IOException {
int ordinal = in.readInt();
if (ordinal < 0 || ordinal >= ENUMS.length) {
throw new RuntimeException("ordinal is out of the range.");
}
return ENUMS[ordinal];
}
} }

View File

@@ -21,10 +21,11 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
import java.io.Serializable; import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class DebugRequest implements Serializable { public class DebugRequest implements Serializable {
private static final long serialVersionUID = 2741129244733000595L;
protected DebugRequestType type; protected DebugRequestType type;
public DebugRequest(DebugRequestType type) { public DebugRequest(DebugRequestType type) {
@@ -41,4 +42,15 @@ public class DebugRequest implements Serializable {
public String toString() { public String toString() {
return type.toString(); return type.toString();
} }
public static void serialize(DataOutputStream out, DebugRequest request)
throws IOException {
DebugRequestType type = request.getType();
SerializationHelper.serialize(type, out);
}
public static DebugRequest deserialize(DataInputStream in) throws IOException {
DebugRequestType type = (DebugRequestType) SerializationHelper.deserialize(in);
return new DebugRequest(type);
}
} }

View File

@@ -21,8 +21,11 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class DebugRequestLineBreakpointToggle extends DebugRequest { public class DebugRequestLineBreakpointToggle extends DebugRequest {
private static final long serialVersionUID = -3954500569399285372L;
protected String source; protected String source;
protected int lineNumber; protected int lineNumber;
@@ -49,4 +52,19 @@ public class DebugRequestLineBreakpointToggle extends DebugRequest {
public String toString() { public String toString() {
return super.toString() + " Source:" + getSource() + " lineNumber:" + getLineNumber(); return super.toString() + " Source:" + getSource() + " lineNumber:" + getLineNumber();
} }
public static void serialize(DataOutputStream out, DebugRequestLineBreakpointToggle request)
throws IOException {
SerializationHelper.serialize(request.getType(), out);
out.writeUTF(request.getSource());
out.writeInt(request.getLineNumber());
}
public static DebugRequest deserialize(DataInputStream in) throws IOException {
DebugRequestType type = (DebugRequestType)SerializationHelper.deserialize(in);
String source = in.readUTF();
int lineNo = in.readInt();
return new DebugRequestLineBreakpointToggle(type, source, lineNo);
}
} }

View File

@@ -21,8 +21,11 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
public class DebugRequestStack extends DebugRequest { import java.io.DataInputStream;
private static final long serialVersionUID = 6270383432060791307L; import java.io.DataOutputStream;
import java.io.IOException;
public class DebugRequestStack extends DebugRequest implements Serializable {
protected int index; protected int index;
public DebugRequestStack(int index) { public DebugRequestStack(int index) {
@@ -40,4 +43,15 @@ public class DebugRequestStack extends DebugRequest {
public String toString() { public String toString() {
return super.toString() + " stack frame:" + getIndex(); return super.toString() + " stack frame:" + getIndex();
} }
public static void serialize(DataOutputStream out, DebugRequestStack request)
throws IOException {
out.writeInt(request.getIndex());
}
public static DebugRequest deserialize(DataInputStream in) throws IOException {
int index = in.readInt();
return new DebugRequestStack(index);
}
} }

View File

@@ -21,9 +21,11 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
import java.io.DataInputStream;
import java.io.IOException;
public class DebugRequestType extends EnumType { public class DebugRequestType extends EnumType {
private static final long serialVersionUID = 2829883820534540402L;
public static final DebugRequestType suspend = new DebugRequestType("suspend", 0); public static final DebugRequestType suspend = new DebugRequestType("suspend", 0);
public static final DebugRequestType resume = new DebugRequestType("resume", 1); public static final DebugRequestType resume = new DebugRequestType("resume", 1);
public static final DebugRequestType exit = new DebugRequestType("exit", 2); public static final DebugRequestType exit = new DebugRequestType("exit", 2);
@@ -34,8 +36,29 @@ public class DebugRequestType extends EnumType {
public static final DebugRequestType callgraph = new DebugRequestType("callgraph", 7); public static final DebugRequestType callgraph = new DebugRequestType("callgraph", 7);
public static final DebugRequestType stack = new DebugRequestType("stack", 8); public static final DebugRequestType stack = new DebugRequestType("stack", 8);
public static final DebugRequestType step = new DebugRequestType("step", 9); public static final DebugRequestType step = new DebugRequestType("step", 9);
protected static final DebugRequestType[] ENUMS = new DebugRequestType[] {
suspend,
resume,
exit,
lineBreakpointSet,
lineBreakpointClear,
watchpointSet,
watchpointClear,
callgraph,
stack,
step
};
public DebugRequestType(String name, int ordinal) { public DebugRequestType(String name, int ordinal) {
super(name, ordinal); super(name, ordinal);
} }
public static DebugRequestType deserialize(DataInputStream in) throws IOException {
int ordinal = in.readInt();
if (ordinal < 0 || ordinal >= ENUMS.length) {
throw new RuntimeException("ordinal is out of the range.");
}
return ENUMS[ordinal];
}
} }

View File

@@ -22,8 +22,6 @@
package lua.debug; package lua.debug;
public class DebugRequestWatchpointToggle extends DebugRequest { public class DebugRequestWatchpointToggle extends DebugRequest {
private static final long serialVersionUID = -2978341358052851046L;
public static class AccessType extends EnumType { public static class AccessType extends EnumType {
private static final long serialVersionUID = 3523086189648091587L; private static final long serialVersionUID = 3523086189648091587L;
@@ -64,4 +62,6 @@ public class DebugRequestWatchpointToggle extends DebugRequest {
public String toString() { public String toString() {
return super.toString() + " functionName:" + getFunctionName() + " variableName:" + getVariableName(); return super.toString() + " functionName:" + getFunctionName() + " variableName:" + getVariableName();
} }
// TODO: add the serialization stuff
} }

View File

@@ -21,4 +21,4 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
public interface DebugResponse {} public interface DebugResponse extends Serializable {}

View File

@@ -21,13 +21,19 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
public class DebugResponseCallgraph extends DebugResponseSimple { import java.io.DataInputStream;
private static final long serialVersionUID = -7761865402188853413L; import java.io.DataOutputStream;
import java.io.IOException;
public class DebugResponseCallgraph implements DebugResponse {
protected StackFrame[] stackFrames; protected StackFrame[] stackFrames;
public DebugResponseCallgraph(StackFrame[] callgraph) { public DebugResponseCallgraph(StackFrame[] callgraph) {
super(true); if (callgraph == null) {
this.stackFrames = callgraph; this.stackFrames = new StackFrame[0];
} else {
this.stackFrames = callgraph;
}
} }
public StackFrame[] getCallgraph() { public StackFrame[] getCallgraph() {
@@ -36,11 +42,30 @@ public class DebugResponseCallgraph extends DebugResponseSimple {
public String toString() { public String toString() {
StringBuilder buffer = new StringBuilder(); StringBuilder buffer = new StringBuilder();
for (int i = 0; stackFrames != null && i < stackFrames.length; i++) { for (int i = 0; i < stackFrames.length; i++) {
StackFrame frame = stackFrames[i]; StackFrame frame = stackFrames[i];
buffer.append(frame.toString()); buffer.append(frame.toString());
buffer.append("\n"); buffer.append("\n");
} }
return buffer.toString(); return buffer.toString();
} }
public static void serialize(DataOutputStream out, DebugResponseCallgraph response)
throws IOException {
StackFrame[] stackFrames = response.getCallgraph();
out.writeInt(stackFrames == null ? 0 : stackFrames.length);
for (int i = 0; stackFrames != null && i < stackFrames.length; i++) {
StackFrame.serialize(out, stackFrames[i]);
}
}
public static DebugResponseCallgraph deserialize(DataInputStream in) throws IOException {
int count = in.readInt();
StackFrame[] stackFrames = new StackFrame[count];
for (int i = 0; i < count; i++) {
stackFrames[i] = StackFrame.deserialize(in);
}
return new DebugResponseCallgraph(stackFrames);
}
} }

View File

@@ -21,11 +21,11 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
import java.io.Serializable; import java.io.DataInputStream;
import java.io.DataOutputStream;
public class DebugResponseSimple implements DebugResponse, Serializable { import java.io.IOException;
private static final long serialVersionUID = 7042417813840650230L;
public class DebugResponseSimple implements DebugResponse {
protected boolean isSuccessful; protected boolean isSuccessful;
public static final DebugResponseSimple SUCCESS = new DebugResponseSimple(true); public static final DebugResponseSimple SUCCESS = new DebugResponseSimple(true);
@@ -45,4 +45,15 @@ public class DebugResponseSimple implements DebugResponse, Serializable {
public String toString() { public String toString() {
return String.valueOf(isSuccessful); return String.valueOf(isSuccessful);
} }
public static void serialize(DataOutputStream out, DebugResponseSimple response)
throws IOException {
out.writeBoolean(response.isSuccessful());
}
public static DebugResponseSimple deserialize(DataInputStream in)
throws IOException {
boolean value = in.readBoolean();
return value ? SUCCESS : FAILURE;
}
} }

View File

@@ -21,13 +21,19 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
public class DebugResponseStack extends DebugResponseSimple { import java.io.DataInputStream;
private static final long serialVersionUID = -2108425321162834731L; import java.io.DataOutputStream;
import java.io.IOException;
public class DebugResponseStack implements DebugResponse {
protected Variable[] variables; protected Variable[] variables;
public DebugResponseStack(Variable[] variables) { public DebugResponseStack(Variable[] variables) {
super(true); if (variables == null) {
this.variables = variables; this.variables = new Variable[0];
} else {
this.variables = variables;
}
} }
public Variable[] getVariables() { public Variable[] getVariables() {
@@ -44,4 +50,22 @@ public class DebugResponseStack extends DebugResponseSimple {
} }
return buffer.toString(); return buffer.toString();
} }
public static void serialize(DataOutputStream out, DebugResponseStack response)
throws IOException {
Variable[] variables = response.getVariables();
out.writeInt(variables == null ? 0 : variables.length);
for (int i = 0; i < variables.length; i++) {
SerializationHelper.serialize(variables[i], out);
}
}
public static DebugResponseStack deserialize(DataInputStream in) throws IOException {
int count = in.readInt();
Variable[] variables = new Variable[count];
for (int i = 0; i < count; i++) {
variables[i] = (Variable) SerializationHelper.deserialize(in);
}
return new DebugResponseStack(variables);
}
} }

View File

@@ -21,12 +21,8 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
import java.util.ArrayList; import java.util.Hashtable;
import java.util.HashMap; import java.util.Vector;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import lua.CallInfo; import lua.CallInfo;
import lua.Lua; import lua.Lua;
@@ -41,12 +37,12 @@ public class DebugStackState extends StackState implements DebugRequestListener
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
protected Map breakpoints = new HashMap(); protected Hashtable breakpoints = new Hashtable();
protected boolean exiting = false; protected boolean exiting = false;
protected boolean suspended = false; protected boolean suspended = false;
protected boolean stepping = false; protected boolean stepping = false;
protected int lastline = -1; protected int lastline = -1;
protected List debugEventListeners = new ArrayList(); protected Vector debugEventListeners = new Vector();
public DebugStackState() { public DebugStackState() {
} }
@@ -130,25 +126,26 @@ public class DebugStackState extends StackState implements DebugRequestListener
// anytime the line doesn't change we keep going // anytime the line doesn't change we keep going
int line = getLineNumber(calls[cc]); int line = getLineNumber(calls[cc]);
if(DebugUtils.IS_DEBUG)
DebugUtils.println("debugHook - executing line: " + line);
if ( !stepping && lastline == line ) { if ( !stepping && lastline == line ) {
return; return;
} }
if(DebugUtils.IS_DEBUG)
DebugUtils.println("debugHook - executing line: " + line);
// save line in case next op is a step // save line in case next op is a step
lastline = line; lastline = line;
if ( stepping ) { if ( stepping ) {
DebugUtils.println("suspended by stepping at pc=" + pc); DebugUtils.println("suspended by stepping at pc=" + pc);
notifyDebugEventListeners(new DebugEventStepping()); //TODO: notifyDebugEventListeners(new DebugEventStepping());
suspended = true; suspended = true;
} else if ( !suspended ) { } else if ( !suspended ) {
// check for a break point if we aren't suspended already // check for a break point if we aren't suspended already
Proto p = calls[cc].closure.p; Proto p = calls[cc].closure.p;
String source = DebugUtils.getSourceFileName(p.source); String source = DebugUtils.getSourceFileName(p.source);
if ( breakpoints.containsKey(constructBreakpointKey(source, line))){ if ( breakpoints.containsKey(constructBreakpointKey(source, line))){
DebugUtils.println("hitting breakpoint " + constructBreakpointKey(source, line)); if(DebugUtils.IS_DEBUG)
DebugUtils.println("hitting breakpoint " + constructBreakpointKey(source, line));
notifyDebugEventListeners( notifyDebugEventListeners(
new DebugEventBreakpoint(source, line)); new DebugEventBreakpoint(source, line));
suspended = true; suspended = true;
@@ -161,7 +158,8 @@ public class DebugStackState extends StackState implements DebugRequestListener
while (suspended && !exiting ) { while (suspended && !exiting ) {
try { try {
this.wait(); this.wait();
DebugUtils.println("resuming execution..."); if(DebugUtils.IS_DEBUG)
DebugUtils.println("resuming execution...");
} catch ( InterruptedException ie ) { } catch ( InterruptedException ie ) {
ie.printStackTrace(); ie.printStackTrace();
} }
@@ -271,7 +269,8 @@ public class DebugStackState extends StackState implements DebugRequestListener
* clear breakpoint at line lineNumber of source source * clear breakpoint at line lineNumber of source source
*/ */
public void clearBreakpoint(String source, int lineNumber) { public void clearBreakpoint(String source, int lineNumber) {
DebugUtils.println("removing breakpoint " + constructBreakpointKey(source, lineNumber)); if(DebugUtils.IS_DEBUG)
DebugUtils.println("removing breakpoint " + constructBreakpointKey(source, lineNumber));
synchronized ( this ) { synchronized ( this ) {
breakpoints.remove(constructBreakpointKey(source, lineNumber)); breakpoints.remove(constructBreakpointKey(source, lineNumber));
} }
@@ -302,24 +301,27 @@ public class DebugStackState extends StackState implements DebugRequestListener
} }
CallInfo callInfo = calls[index]; CallInfo callInfo = calls[index];
DebugUtils.println("Stack Frame: " + index + "[" + callInfo.base + "," + callInfo.top + "]"); if(DebugUtils.IS_DEBUG)
DebugUtils.println("Stack Frame: " + index + "[" + callInfo.base + "," + callInfo.top + "]");
int top = callInfo.top < callInfo.base ? callInfo.base : callInfo.top; int top = callInfo.top < callInfo.base ? callInfo.base : callInfo.top;
Proto prototype = callInfo.closure.p; Proto prototype = callInfo.closure.p;
LocVars[] localVariables = prototype.locvars; LocVars[] localVariables = prototype.locvars;
List variables = new ArrayList(); Vector variables = new Vector();
int localVariableCount = 0; int localVariableCount = 0;
Set variablesSeen = new HashSet(); Hashtable variablesSeen = new Hashtable();
for (int i = 0; localVariables != null && i < localVariables.length && i <= top; i++) { for (int i = 0; localVariables != null && i < localVariables.length && i <= top; i++) {
String varName = localVariables[i].varname.toString(); String varName = localVariables[i].varname.toString();
DebugUtils.print("\tVariable: " + varName); if(DebugUtils.IS_DEBUG) {
DebugUtils.print("\tValue: " + stack[callInfo.base + i]); DebugUtils.print("\tVariable: " + varName);
DebugUtils.print("\tValue: " + stack[callInfo.base + i]);
}
if (!variablesSeen.contains(varName) && if (!variablesSeen.contains(varName) &&
!LexState.isReservedKeyword(varName)) { !LexState.isReservedKeyword(varName)) {
variablesSeen.add(varName); variablesSeen.put(varName, varName);
LValue value = stack[callInfo.base + i]; LValue value = stack[callInfo.base + i];
if (value != null) { if (value != null) {
int type = value.luaGetType(); int type = value.luaGetType();
DebugUtils.print("\tType: " + type); DebugUtils.print("\tType: " + Lua.TYPE_NAMES[type]);
if (type == Lua.LUA_TTABLE) { if (type == Lua.LUA_TTABLE) {
DebugUtils.println(" (selected)"); DebugUtils.println(" (selected)");
variables.add( variables.add(

View File

@@ -21,24 +21,36 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
public class DebugSupport implements DebugEventListener { public class DebugSupport implements DebugEventListener {
public static class State extends EnumType { public static class State extends EnumType {
private static final long serialVersionUID = 3657364516937093612L;
public static final State UNKNOWN = new State("UNKNOWN", 0); public static final State UNKNOWN = new State("UNKNOWN", 0);
public static final State RUNNING = new State("RUNNING", 1); public static final State RUNNING = new State("RUNNING", 1);
public static final State STOPPED = new State("STOPPED", 2); public static final State STOPPED = new State("STOPPED", 2);
protected static final State[] ENUMS = new State[] {
UNKNOWN,
RUNNING,
STOPPED
};
public State(String name, int ordinal) { public State(String name, int ordinal) {
super(name, ordinal); super(name, ordinal);
} }
public static State deserialize(DataInputStream in) throws IOException {
int ordinal = in.readInt();
if (ordinal < 0 || ordinal >= ENUMS.length) {
throw new RuntimeException("ordinal is out of the range.");
}
return ENUMS[ordinal];
}
} }
protected DebugRequestListener listener; protected DebugRequestListener listener;
@@ -49,12 +61,12 @@ public class DebugSupport implements DebugEventListener {
protected ServerSocket requestSocket; protected ServerSocket requestSocket;
protected Socket clientRequestSocket; protected Socket clientRequestSocket;
protected ObjectInputStream requestReader; protected DataInputStream requestReader;
protected ObjectOutputStream requestWriter; protected DataOutputStream requestWriter;
protected ServerSocket eventSocket; protected ServerSocket eventSocket;
protected Socket clientEventSocket; protected Socket clientEventSocket;
protected ObjectOutputStream eventWriter; protected DataOutputStream eventWriter;
public DebugSupport(DebugRequestListener listener, public DebugSupport(DebugRequestListener listener,
int requestPort, int requestPort,
@@ -117,14 +129,14 @@ public class DebugSupport implements DebugEventListener {
this.requestSocket = new ServerSocket(requestPort); this.requestSocket = new ServerSocket(requestPort);
this.clientRequestSocket = requestSocket.accept(); this.clientRequestSocket = requestSocket.accept();
this.requestReader this.requestReader
= new ObjectInputStream(clientRequestSocket.getInputStream()); = new DataInputStream(clientRequestSocket.getInputStream());
this.requestWriter this.requestWriter
= new ObjectOutputStream(clientRequestSocket.getOutputStream()); = new DataOutputStream(clientRequestSocket.getOutputStream());
this.eventSocket = new ServerSocket(eventPort); this.eventSocket = new ServerSocket(eventPort);
this.clientEventSocket = eventSocket.accept(); this.clientEventSocket = eventSocket.accept();
this.eventWriter this.eventWriter
= new ObjectOutputStream(clientEventSocket.getOutputStream()); = new DataOutputStream(clientEventSocket.getOutputStream());
this.requestWatcherThread = new Thread(new Runnable() { this.requestWatcherThread = new Thread(new Runnable() {
public void run() { public void run() {
@@ -151,11 +163,17 @@ public class DebugSupport implements DebugEventListener {
synchronized (clientRequestSocket) { synchronized (clientRequestSocket) {
try { try {
while (getState() != State.STOPPED) { while (getState() != State.STOPPED) {
int size = requestReader.readInt();
byte[] data = new byte[size];
requestReader.readFully(data);
DebugRequest request DebugRequest request
= (DebugRequest) requestReader.readObject(); = (DebugRequest) SerializationHelper.deserialize(data);
DebugUtils.println("SERVER receives request: " + request.toString()); DebugUtils.println("SERVER receives request: " + request.toString());
DebugResponse response = listener.handleRequest(request); DebugResponse response = listener.handleRequest(request);
requestWriter.writeObject(response); data = SerializationHelper.serialize(response);
requestWriter.writeInt(data.length);
requestWriter.write(data);
requestWriter.flush(); requestWriter.flush();
DebugUtils.println("SERVER sends response: " + response); DebugUtils.println("SERVER sends response: " + response);
} }
@@ -167,8 +185,6 @@ public class DebugSupport implements DebugEventListener {
cleanup(); cleanup();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} }
} }
} }
@@ -203,7 +219,9 @@ public class DebugSupport implements DebugEventListener {
DebugUtils.println("SERVER sending event: " + event.toString()); DebugUtils.println("SERVER sending event: " + event.toString());
synchronized (eventSocket) { synchronized (eventSocket) {
try { try {
eventWriter.writeObject(event); byte[] data = SerializationHelper.serialize(event);
eventWriter.writeInt(data.length);
eventWriter.write(data);
eventWriter.flush(); eventWriter.flush();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();

View File

@@ -27,7 +27,7 @@ import lua.io.LoadState;
import lua.value.LString; import lua.value.LString;
public class DebugUtils { public class DebugUtils {
public static final boolean IS_DEBUG = false; public static final boolean IS_DEBUG = true;
public static void println(String message) { public static void println(String message) {
if (IS_DEBUG) { if (IS_DEBUG) {

View File

@@ -21,24 +21,17 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
public class EnumType implements Serializable {
private static final long serialVersionUID = -496099911938395074L; public abstract class EnumType implements Serializable {
protected String name; protected String name;
protected int ordinal; protected int ordinal;
protected static Map lookup = new HashMap();
public EnumType(String name, int ordinal) { public EnumType(String name, int ordinal) {
this.name = name; this.name = name;
this.ordinal = ordinal; this.ordinal = ordinal;
lookup.put(name, this);
} }
public String toString() { public String toString() {
@@ -60,4 +53,8 @@ public class EnumType implements Serializable {
public final int ordinal() { public final int ordinal() {
return this.ordinal; return this.ordinal;
} }
public static void serialize(DataOutputStream out, EnumType enumType) throws IOException {
out.writeInt(enumType.ordinal());
}
} }

View File

@@ -0,0 +1,53 @@
/*******************************************************************************
* Copyright (c) 2007 LuaJ. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package lua.debug;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class NullableString implements Serializable {
protected String string;
public NullableString(String someString) {
this.string = someString;
}
public String getNullableString() {
return (this.string == null) ? "[NULL]" : this.string;
}
public String getRawString() {
return (this.string.equals("[NULL]")) ? null : this.string;
}
public static void serialize(DataOutputStream out, NullableString string)
throws IOException {
out.writeUTF(string.getNullableString());
}
public static NullableString deserialize(DataInputStream in)
throws IOException {
String string = in.readUTF();
return new NullableString(string);
}
}

View File

@@ -21,10 +21,6 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
public class DebugEventStepping extends DebugEvent {
private static final long serialVersionUID = 3902898567880012107L;
public DebugEventStepping() {
super(DebugEventType.suspendedOnStepping); public interface Serializable { }
}
}

View File

@@ -0,0 +1,163 @@
package lua.debug;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class SerializationHelper {
public static byte[] serialize(Serializable object) throws IOException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(bout);
serialize(object, dout);
byte[] data = bout.toByteArray();
bout.close();
dout.close();
return data;
}
public static Serializable deserialize(byte[] data) throws IOException {
ByteArrayInputStream bin = new ByteArrayInputStream(data);
DataInputStream din = new DataInputStream(bin);
Serializable object = deserialize(din);
bin.close();
din.close();
return object;
}
static final int SERIAL_TYPE_NullableString = 0;
static final int SERIAL_TYPE_TableVariable = 1;
static final int SERIAL_TYPE_Variable = 2;
static final int SERIAL_TYPE_DebugResponseCallgraph = 3;
static final int SERIAL_TYPE_DebugResponseStack = 4;
static final int SERIAL_TYPE_DebugResponseSimple = 5;
static final int SERIAL_TYPE_DebugSupportState = 6;
static final int SERIAL_TYPE_StackFrame = 7;
static final int SERIAL_TYPE_DebugRequestType = 8;
static final int SERIAL_TYPE_DebugRequest = 9;
static final int SERIAL_TYPE_DebugRequestStack = 10;
static final int SERIAL_TYPE_DebugRequestLineBreakpointToggle = 11;
static final int SERIAL_TYPE_DebugEventType = 12;
static final int SERIAL_TYPE_DebugEvent = 13;
static final int SERIAL_TYPE_DebugEventBreakpoint = 14;
public static void serialize(Serializable object, DataOutputStream dout)
throws IOException {
if (object instanceof NullableString) {
dout.writeInt(SERIAL_TYPE_NullableString);
NullableString.serialize(dout, (NullableString)object);
} else if (object instanceof TableVariable) {
dout.writeInt(SERIAL_TYPE_TableVariable);
TableVariable.serialize(dout, (TableVariable)object);
} else if (object instanceof Variable) {
dout.writeInt(SERIAL_TYPE_Variable);
Variable.serialize(dout, (Variable)object);
} else if (object instanceof StackFrame) {
dout.writeInt(SERIAL_TYPE_StackFrame);
StackFrame.serialize(dout, (StackFrame)object);
} else if (object instanceof DebugResponseSimple) {
dout.writeInt(SERIAL_TYPE_DebugResponseSimple);
DebugResponseSimple.serialize(dout, (DebugResponseSimple)object);
} else if (object instanceof DebugResponseStack) {
dout.writeInt(SERIAL_TYPE_DebugResponseStack);
DebugResponseStack.serialize(dout, (DebugResponseStack)object);
} else if (object instanceof DebugResponseCallgraph) {
dout.writeInt(SERIAL_TYPE_DebugResponseCallgraph);
DebugResponseCallgraph.serialize(dout, (DebugResponseCallgraph)object);
} else if (object instanceof DebugSupport.State) {
dout.writeInt(SERIAL_TYPE_DebugSupportState);
DebugSupport.State.serialize(dout, (DebugSupport.State)object);
} else if (object instanceof DebugRequestType) {
dout.writeInt(SERIAL_TYPE_DebugRequestType);
DebugRequestType.serialize(dout, (DebugRequestType)object);
} else if (object instanceof DebugRequestStack) {
dout.writeInt(SERIAL_TYPE_DebugRequestStack);
DebugRequestStack.serialize(dout, (DebugRequestStack)object);
} else if (object instanceof DebugRequestLineBreakpointToggle) {
dout.writeInt(SERIAL_TYPE_DebugRequestLineBreakpointToggle);
DebugRequestLineBreakpointToggle.serialize(dout, (DebugRequestLineBreakpointToggle)object);
} else if (object instanceof DebugRequest) {
dout.writeInt(SERIAL_TYPE_DebugRequest);
DebugRequest.serialize(dout, (DebugRequest)object);
} else if (object instanceof DebugEventType) {
dout.writeInt(SERIAL_TYPE_DebugEventType);
DebugEventType.serialize(dout, (DebugEventType)object);
} else if (object instanceof DebugEventBreakpoint) {
dout.writeInt(SERIAL_TYPE_DebugEventBreakpoint);
DebugEventBreakpoint.serialize(dout, (DebugEventBreakpoint)object);
} else if (object instanceof DebugEvent) {
dout.writeInt(SERIAL_TYPE_DebugEvent);
DebugEvent.serialize(dout, (DebugEvent)object);
} else {
// catch the errors: forgot to implement serialization/deserialization
throw new RuntimeException("serialization operation is not supported");
}
}
public static Serializable deserialize(DataInputStream din)
throws IOException {
Serializable object = null;
int type = din.readInt();
switch (type) {
case SERIAL_TYPE_NullableString:
object = NullableString.deserialize(din);
break;
case SERIAL_TYPE_TableVariable:
object = TableVariable.deserialize(din);
break;
case SERIAL_TYPE_Variable:
object = Variable.deserialize(din);
break;
case SERIAL_TYPE_StackFrame:
object = StackFrame.deserialize(din);
break;
case SERIAL_TYPE_DebugResponseSimple:
object = DebugResponseSimple.deserialize(din);
break;
case SERIAL_TYPE_DebugResponseCallgraph:
object = DebugResponseCallgraph.deserialize(din);
break;
case SERIAL_TYPE_DebugResponseStack:
object = DebugResponseStack.deserialize(din);
break;
case SERIAL_TYPE_DebugSupportState:
object = DebugSupport.State.deserialize(din);
break;
case SERIAL_TYPE_DebugRequestType:
object = DebugRequestType.deserialize(din);
break;
case SERIAL_TYPE_DebugRequestStack:
object = DebugRequestStack.deserialize(din);
break;
case SERIAL_TYPE_DebugRequestLineBreakpointToggle:
object = DebugRequestLineBreakpointToggle.deserialize(din);
break;
case SERIAL_TYPE_DebugRequest:
object = DebugRequest.deserialize(din);
break;
case SERIAL_TYPE_DebugEventType:
object = DebugEventType.deserialize(din);
break;
case SERIAL_TYPE_DebugEventBreakpoint:
object = DebugEventBreakpoint.deserialize(din);
break;
case SERIAL_TYPE_DebugEvent:
object = DebugEvent.deserialize(din);
break;
default:
throw new RuntimeException("deserialization operation is not supported");
}
return object;
}
}

View File

@@ -42,23 +42,25 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
import java.io.Serializable; import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import lua.CallInfo; import lua.CallInfo;
import lua.io.Proto;
public class StackFrame implements Serializable { public class StackFrame implements Serializable {
private static final long serialVersionUID = 2102834561519501432L;
protected int lineNumber; protected int lineNumber;
protected String source; protected String source;
public StackFrame(CallInfo callInfo, int lineNumber) { public StackFrame(CallInfo callInfo, int lineNumber) {
Proto prototype = callInfo.closure.p; this(lineNumber, DebugUtils.getSourceFileName(callInfo.closure.p.source));
this.lineNumber = lineNumber;
this.source = DebugUtils.getSourceFileName(prototype.source);
} }
StackFrame(int lineNumber, String source) {
this.lineNumber = lineNumber;
this.source = source;
}
public int getLineNumber() { public int getLineNumber() {
return this.lineNumber; return this.lineNumber;
} }
@@ -73,4 +75,41 @@ public class StackFrame implements Serializable {
public String toString() { public String toString() {
return getSource() + ":" + getLineNumber(); return getSource() + ":" + getLineNumber();
} }
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + lineNumber;
result = prime * result + ((source == null) ? 0 : source.hashCode());
return result;
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final StackFrame other = (StackFrame) obj;
if (lineNumber != other.lineNumber)
return false;
if (source == null) {
if (other.source != null)
return false;
} else if (!source.equals(other.source))
return false;
return true;
}
public static void serialize(DataOutputStream out, StackFrame stackFrame) throws IOException {
out.writeInt(stackFrame.getLineNumber());
out.writeUTF(stackFrame.getSource());
}
public static StackFrame deserialize(DataInputStream in) throws IOException {
int lineNumber = in.readInt();
String source = in.readUTF();
return new StackFrame(lineNumber, source);
}
} }

View File

@@ -40,22 +40,13 @@ import lua.io.Proto;
import lua.value.LString; import lua.value.LString;
import lua.value.LValue; import lua.value.LValue;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
/** /**
* StandardLuaJVM executes a lua program in normal run mode or debug mode. * StandardLuaJVM executes a lua program in normal run mode or debug mode.
* *
* @author: Shu Lei * @author: Shu Lei
* @version: 1.0 * @version: 1.0
*/ */
public class StandardLuaJVM implements DebugRequestListener { public class StandardLuaJVM implements DebugRequestListener {
protected Options options = new Options();
protected boolean isDebugMode = false; protected boolean isDebugMode = false;
protected DebugSupport debugSupport; protected DebugSupport debugSupport;
protected int requestPort; protected int requestPort;
@@ -64,88 +55,104 @@ public class StandardLuaJVM implements DebugRequestListener {
protected String[] scriptArgs; protected String[] scriptArgs;
protected StackState state; protected StackState state;
protected boolean isReady = false; protected boolean isReady = false;
protected boolean isTerminated = false; protected boolean isTerminated = false;
public StandardLuaJVM() { // command line parsing utilities
options.addOption(OptionBuilder.withArgName("requestPort eventPort"). class ParseException extends Exception {
hasArgs(2). private static final long serialVersionUID = -3134938136698856577L;
isRequired(false).
withValueSeparator(' '). public ParseException(String message) {
withDescription("run LuaJ VM in debug mode"). super(message);
create("debug")); }
options.addOption(OptionBuilder.withArgName("LuaJProgram").
withDescription("lua program to be executed").
isRequired().
hasArgs().
withValueSeparator(' ').
create("file"));
} }
protected void printUsage() { protected void printUsage() {
HelpFormatter formatter = new HelpFormatter(); System.out.println("Usage:");
formatter.printHelp("java StandardLuaJVM", options); System.out.println("\t java StandardLuaJVM [-debug <requestPort> <eventPort>] <script> [<script arguments>]");
System.out.println("where [] denotes an optional argument and <> denotes a placeholder.");
} }
protected void parse(String[] args) throws ParseException { void parse(String[] args) throws ParseException {
CommandLineParser parser = new GnuParser(); if (args == null || args.length < 1) {
try { throw new ParseException("Invalid command line arguments.");
CommandLine line = parser.parse(options, args); }
if (line.hasOption("debug")) {
this.isDebugMode = true;
String[] ports = line.getOptionValues("debug");
this.requestPort = Integer.parseInt(ports[0]);
if (this.requestPort <= 0) {
throw new ParseException("Invalid request port: it must be greater than zero.");
}
this.eventPort = Integer.parseInt(ports[1]);
if (this.eventPort <= 0) {
throw new ParseException("Invalid event port: it must be greater than zero.");
}
if (this.requestPort == this.eventPort) {
throw new ParseException("Invalid ports: request port and event port must be different");
}
}
if (line.hasOption("file")) { if ("-debug".equals(args[0])) {
String[] fileArgs = line.getOptionValues("file"); if (args.length < 4) {
this.script = URLDecoder.decode(fileArgs[0], "UTF-8"); throw new ParseException("Invalid command line arguments.");
DebugUtils.println("Lua script to run: " + this.script); }
this.scriptArgs = new String[fileArgs.length - 1];
for (int i = 1; i < fileArgs.length; i++) { this.isDebugMode = true;
this.scriptArgs[i-1] = URLDecoder.decode(fileArgs[i], "UTF-8"); try {
} this.requestPort = Integer.parseInt(args[1]);
if (this.requestPort <= 0) {
throw new ParseException("Invalid request port: it must be greater than zero.");
}
this.eventPort = Integer.parseInt(args[2]);
if (this.eventPort <= 0) {
throw new ParseException("Invalid event port: it must be greater than zero.");
}
} catch(NumberFormatException e) {
throw new ParseException("Invalid port number: " + e.getMessage());
}
if (this.requestPort == this.eventPort) {
throw new ParseException("Invalid ports: request port and event port must be different");
} }
} catch(NumberFormatException e) {
throw new ParseException("Invalid port number: " + e.getMessage()); int tempArgsCount = args.length - 3;
} catch (UnsupportedEncodingException e) { String[] tempArgs = new String[tempArgsCount];
throw new ParseException("Malformed program argument strings: " + e.getMessage()); System.arraycopy(args, 3, tempArgs, 0, tempArgsCount);
} parseScriptArgs(tempArgs);
} else {
parseScriptArgs(args);
}
} }
protected boolean isDebug() { private void parseScriptArgs(String[] args)
throws lua.debug.StandardLuaJVM.ParseException {
if (args == null || args.length < 1) {
throw new ParseException("script is missing.");
}
try {
this.script = URLDecoder.decode(args[0], "UTF-8");
DebugUtils.println("Lua script to run: " + this.script);
int scriptArgsLength = args.length - 1;
if (scriptArgsLength > 0) {
this.scriptArgs = new String[scriptArgsLength];
for (int i = 1; i < args.length; i++) {
this.scriptArgs[i - 1] = URLDecoder.decode(args[i], "UTF-8");
}
}
} catch (UnsupportedEncodingException e) {
throw new ParseException("Malformed program argument strings: " + e.getMessage());
}
}
// end of command line parsing utilities
boolean isDebug() {
return this.isDebugMode; return this.isDebugMode;
} }
protected int getRequestPort() { int getRequestPort() {
return this.requestPort; return this.requestPort;
} }
protected int getEventPort() { int getEventPort() {
return this.eventPort; return this.eventPort;
} }
protected String getScript() { String getScript() {
return this.script; return this.script;
} }
protected boolean hasScriptArgs() { boolean hasScriptArgs() {
return (this.scriptArgs != null && this.scriptArgs.length > 0); return (this.scriptArgs != null && this.scriptArgs.length > 0);
} }
protected String[] getScriptArgs() { String[] getScriptArgs() {
return this.scriptArgs; return this.scriptArgs;
} }
@@ -175,7 +182,8 @@ public class StandardLuaJVM implements DebugRequestListener {
state = new StackState(); state = new StackState();
// convert args to lua // convert args to lua
int numOfScriptArgs = getScriptArgs().length; String[] scriptArgs = getScriptArgs();
int numOfScriptArgs = (scriptArgs == null) ? 0 : scriptArgs.length;
LValue[] vargs = new LValue[numOfScriptArgs]; LValue[] vargs = new LValue[numOfScriptArgs];
for (int i = 0; i < numOfScriptArgs; i++) { for (int i = 0; i < numOfScriptArgs; i++) {
vargs[i] = new LString(getScriptArgs()[i]); vargs[i] = new LString(getScriptArgs()[i]);
@@ -191,35 +199,36 @@ public class StandardLuaJVM implements DebugRequestListener {
state.doCall(c, vargs); state.doCall(c, vargs);
} }
private void doDebug() throws IOException { private void doDebug() throws IOException {
DebugUtils.println("start debugging..."); DebugUtils.println("setting up LuaJava and debug stack state...");
this.debugSupport = new DebugSupport(this, getRequestPort(), getEventPort());
DebugUtils.println("created client request socket connection...");
debugSupport.start();
DebugUtils.println("setting up LuaJava and debug stack state...");
init(); init();
// new lua state
state = new DebugStackState();
getDebugState().addDebugEventListener(debugSupport);
// load the Lua file // load the Lua file
DebugUtils.println("loading Lua script '" + getScript() + "'"); DebugUtils.println("loading Lua script '" + getScript() + "'");
InputStream is = new FileInputStream(new File(getScript())); InputStream is = new FileInputStream(new File(getScript()));
Proto p = LoadState.undump(state, is, getScript()); Proto p = LoadState.undump(state, is, getScript());
// set up debug support if the file is successfully loaded
DebugUtils.println("start debugging...");
this.debugSupport = new DebugSupport(this, getRequestPort(), getEventPort());
DebugUtils.println("created client request socket connection...");
debugSupport.start();
// new lua debug state
state = new DebugStackState();
getDebugState().addDebugEventListener(debugSupport);
getDebugState().suspend();
// create closure and execute // create closure and execute
final Closure c = new Closure(state, p); final Closure c = new Closure(state, p);
getDebugState().suspend();
new Thread(new Runnable() { new Thread(new Runnable() {
public void run() { public void run() {
int numOfScriptArgs = getScriptArgs().length; String[] args = getScriptArgs();
int numOfScriptArgs = (args != null ? args.length : 0);
LValue[] vargs = new LValue[numOfScriptArgs]; LValue[] vargs = new LValue[numOfScriptArgs];
for (int i = 0; i < numOfScriptArgs; i++) { for (int i = 0; i < numOfScriptArgs; i++) {
vargs[i] = new LString(getScriptArgs()[i]); vargs[i] = new LString(args[i]);
} }
getDebugState().doCall(c, vargs); getDebugState().doCall(c, vargs);
@@ -281,25 +290,21 @@ public class StandardLuaJVM implements DebugRequestListener {
/** /**
* Parses the command line arguments and executes/debugs the lua program. * Parses the command line arguments and executes/debugs the lua program.
* @param args -- command line arguments: * @param args -- command line arguments:
* [-debug requestPort eventPort] -file luaProgram args * [-debug <requestPort> <eventPort>] <script> <script arguments separated by a whitespace>
* @throws IOException
*/ */
public static void main(String[] args) { public static void main(String[] args) {
StandardLuaJVM vm = new StandardLuaJVM(); StandardLuaJVM vm = new StandardLuaJVM();
try { try {
vm.parse(args); vm.parse(args);
vm.run();
} catch (ParseException e) { } catch (ParseException e) {
DebugUtils.println(e.getMessage()); System.out.println("Error: " + e.getMessage());
vm.printUsage(); vm.printUsage();
return; return;
}
try {
vm.run();
} catch (IOException e) { } catch (IOException e) {
//TODO: handle the error System.out.println("Error: " + e.getMessage());
e.printStackTrace(); e.printStackTrace();
} }
} }
} }

View File

@@ -21,16 +21,16 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
import java.util.ArrayList; import java.io.DataInputStream;
import java.util.List; import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Vector;
import lua.Lua; import lua.Lua;
import lua.value.LTable; import lua.value.LTable;
import lua.value.LValue; import lua.value.LValue;
public class TableVariable extends Variable { public class TableVariable extends Variable {
private static final long serialVersionUID = 1194778378382802700L;
protected String[] keys; protected String[] keys;
protected Object[] values; protected Object[] values;
@@ -39,8 +39,8 @@ public class TableVariable extends Variable {
int size = table.size(); int size = table.size();
DebugUtils.println("table size:" + size); DebugUtils.println("table size:" + size);
List keyArray = new ArrayList(); Vector keyArray = new Vector();
List valueArray = new ArrayList(); Vector valueArray = new Vector();
LValue[] keyValues = table.getKeys(); LValue[] keyValues = table.getKeys();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
@@ -60,14 +60,73 @@ public class TableVariable extends Variable {
} }
this.keys = (String[])keyArray.toArray(new String[0]); this.keys = (String[])keyArray.toArray(new String[0]);
this.values = valueArray.toArray(); this.values = (Object[]) valueArray.toArray(new Object[0]);
if (this.keys.length != this.values.length) {
throw new RuntimeException("Internal Error: key.length must equal to values.length");
}
}
public TableVariable(int index, String name, int type, String[] keys, Object[] values) {
super(index, name, type, null);
this.keys = keys;
this.values = values;
} }
public String[] getKeys() { public String[] getKeys() {
return this.keys; return this.keys == null ? new String[0] : this.keys;
} }
public Object[] getValues() { public Object[] getValues() {
return this.values; return this.values == null ? new Object[0] : this.values;
} }
public static void serialize(DataOutputStream out, TableVariable variable) throws IOException {
out.writeInt(variable.getIndex());
out.writeUTF(variable.getName());
out.writeInt(variable.getType());
String[] keys = variable.getKeys();
out.writeInt(keys.length);
for (int i = 0; keys != null && i < keys.length; i++) {
SerializationHelper.serialize(new NullableString(keys[i]), out);
}
Object[] values = variable.getValues();
for (int i = 0; values != null && i < values.length; i++) {
if (values[i] instanceof String) {
SerializationHelper.serialize(new NullableString((String)values[i]), out);
} else if (values[i] instanceof TableVariable) {
SerializationHelper.serialize((TableVariable)values[i], out);
} else {
throw new RuntimeException("Internal Error: values array should only contain String and TableVariable");
}
}
}
public static Variable deserialize(DataInputStream in) throws IOException {
int index = in.readInt();
String name = in.readUTF();
int type = in.readInt();
String[] keys = null;
Object[] values = null;
int count = in.readInt();
keys = new String[count];
for (int i = 0; i < count; i++) {
keys[i] = ((NullableString) SerializationHelper.deserialize(in)).getRawString();
}
values = new Object[count];
for (int i = 0; i < count; i++) {
int serialType = in.readInt();
if (serialType == SerializationHelper.SERIAL_TYPE_NullableString) {
values[i] = NullableString.deserialize(in).getRawString();
} else if (serialType == SerializationHelper.SERIAL_TYPE_TableVariable) {
values[i] = TableVariable.deserialize(in);
}
}
TableVariable variable = new TableVariable(index, name, type, keys, values);
return variable;
}
} }

View File

@@ -21,19 +21,27 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
import java.io.Serializable; import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import lua.Lua; import lua.Lua;
public class Variable implements Serializable { public class Variable implements Serializable {
private static final long serialVersionUID = 8194091816623233934L;
protected int index; protected int index;
protected String name; protected String name;
protected String value; protected String value;
protected int type; protected int type;
public Variable(int index, String name, int type, String value) { public Variable(int index, String name, int type, String value) {
if (name == null) {
throw new IllegalArgumentException("argument name is null");
}
if (type < Lua.LUA_TNIL || type > Lua.LUA_TTHREAD) {
throw new IllegalArgumentException("invalid LValue type: " + type);
}
this.index = index; this.index = index;
this.name = name; this.name = name;
this.type = type; this.type = type;
@@ -59,4 +67,57 @@ public class Variable implements Serializable {
public String toString() { public String toString() {
return "index: " + getIndex() + " name:" + getName() + " type: " + Lua.TYPE_NAMES[getType()] + " value:" + getValue(); return "index: " + getIndex() + " name:" + getName() + " type: " + Lua.TYPE_NAMES[getType()] + " value:" + getValue();
} }
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + index;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + type;
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Variable other = (Variable) obj;
if (index != other.index)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (type != other.type)
return false;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
public static void serialize(DataOutputStream out, Variable variable)
throws IOException {
out.writeInt(variable.getIndex());
out.writeUTF(variable.getName());
out.writeInt(variable.getType());
SerializationHelper.serialize(new NullableString(variable.getValue()), out);
}
public static Variable deserialize(DataInputStream in) throws IOException {
int index = in.readInt();
String name = in.readUTF();
int type = in.readInt();
NullableString value = (NullableString)SerializationHelper.deserialize(in);
Variable variable = new Variable(index, name, type, value.getRawString());
return variable;
}
} }

View File

@@ -0,0 +1,33 @@
package lua.debug;
import java.io.IOException;
import junit.framework.TestCase;
public class DebugEventTest extends TestCase {
public void testDebugEventSerialization() {
try {
DebugEvent event = new DebugEvent(DebugEventType.started);
byte[] data = SerializationHelper.serialize(event);
DebugEvent eventOut = (DebugEvent)SerializationHelper.deserialize(data);
assertNotNull(eventOut);
assertEquals(event.getType(), eventOut.getType());
} catch (IOException e) {
fail(e.getMessage());
}
}
public void testDebugEventBreakpointSerialization() {
try {
DebugEventBreakpoint event = new DebugEventBreakpoint("test.lua", 100);
byte[] data = SerializationHelper.serialize(event);
DebugEventBreakpoint eventOut
= (DebugEventBreakpoint) SerializationHelper.deserialize(data);
assertNotNull(eventOut);
assertEquals(event.getSource(), eventOut.getSource());
assertEquals(event.getLineNumber(), eventOut.getLineNumber());
} catch (IOException e) {
fail(e.getMessage());
}
}
}

View File

@@ -0,0 +1,56 @@
package lua.debug;
import java.io.IOException;
import junit.framework.TestCase;
public class DebugRequestTest extends TestCase {
public void testDebugRequestSerialization() {
try {
DebugRequest request = new DebugRequest(DebugRequestType.resume);
byte[] data = SerializationHelper.serialize(request);
DebugRequest requestOut
= (DebugRequest)SerializationHelper.deserialize(data);
assertNotNull(requestOut);
assertEquals(request.getType(), requestOut.getType());
} catch (IOException e) {
fail(e.getMessage());
}
}
public void testDebugRequestStackSerialization() {
try {
DebugRequestStack request = new DebugRequestStack(1);
byte[] data = SerializationHelper.serialize(request);
DebugRequestStack requestOut
= (DebugRequestStack) SerializationHelper.deserialize(data);
assertNotNull(requestOut);
assertEquals(requestOut.getIndex(), 1);
} catch (IOException e) {
fail(e.getMessage());
}
}
public void testDebugRequestLineBreakpointToggleSerialization() {
try
{
doTestDebugRequestLineBreakpointToggleSerialization(DebugRequestType.lineBreakpointSet, "test.lua", 100);
doTestDebugRequestLineBreakpointToggleSerialization(DebugRequestType.lineBreakpointClear, "test.lua", 50);
} catch (IOException e) {
fail(e.getMessage());
}
}
private void doTestDebugRequestLineBreakpointToggleSerialization(
DebugRequestType type, String source, int lineNo) throws IOException {
DebugRequestLineBreakpointToggle request
= new DebugRequestLineBreakpointToggle(DebugRequestType.lineBreakpointSet, "test.lua", 100);
byte[] data = SerializationHelper.serialize(request);
DebugRequestLineBreakpointToggle requestOut =
(DebugRequestLineBreakpointToggle) SerializationHelper.deserialize(data);
assertNotNull(requestOut);
assertEquals(request.getType(), requestOut.getType());
assertEquals(request.getSource(), requestOut.getSource());
assertEquals(request.getLineNumber(), requestOut.getLineNumber());
}
}

View File

@@ -0,0 +1,88 @@
package lua.debug;
import java.io.IOException;
import junit.framework.TestCase;
import lua.Lua;
public class DebugResponseTest extends TestCase {
public void testDebugResponseSimpleSerialization() {
try {
DebugResponseSimple responseIn = DebugResponseSimple.SUCCESS;
byte[] data = SerializationHelper.serialize(responseIn);
DebugResponseSimple responseOut
= (DebugResponseSimple)SerializationHelper.deserialize(data);
assertEquals(responseIn, responseOut);
} catch (IOException e) {
fail(e.getMessage());
}
}
public void testDebugResponseStackSerialization() {
try {
doTestDebugResponseStackSerialization(null);
doTestDebugResponseStackSerialization(new Variable[0]);
Variable[] variables = new Variable[5];
variables[0] = new Variable(0, "variable1", Lua.LUA_TSTRING, "value1");
variables[1] = new Variable(1, "variable2", Lua.LUA_TNIL, "nil");
variables[2] = new Variable(2, "variable3", Lua.LUA_TBOOLEAN, "false");
TableVariable childTable = new TableVariable(0, "child", Lua.LUA_TTABLE, new String[0], new Object[0]);
String[] keys = new String[] {"key1", "key2"};
Object[] values = new Object[] {"value1", childTable};
variables[3] = new TableVariable(2, "variable4", Lua.LUA_TTABLE, keys, values);
variables[4] = new Variable(2, "variable3", Lua.LUA_TNUMBER, "10");
doTestDebugResponseStackSerialization(variables);
} catch (IOException e) {
fail(e.getMessage());
}
}
private void doTestDebugResponseStackSerialization(Variable[] variables)
throws IOException {
DebugResponseStack stackIn = new DebugResponseStack(variables);
byte[] data = SerializationHelper.serialize(stackIn);
DebugResponseStack stackOut
= (DebugResponseStack) SerializationHelper.deserialize(data);
Variable[] variablesIn = stackIn.getVariables();
Variable[] variablesOut = stackOut.getVariables();
assertNotNull(variablesIn);
assertNotNull(variablesOut);
assertEquals(variablesIn.length, variablesOut.length);
for (int i = 0; i < variablesIn.length; i++) {
assertEquals(variablesIn[i], variablesOut[i]);
}
}
public void testDebugResponseCallgraphSerialization() {
try {
doTestDebugResponseCallgraphSerialization(null);
doTestDebugResponseCallgraphSerialization(new StackFrame[0]);
StackFrame[] frames = new StackFrame[1];
frames[0] = new StackFrame(100, "test.lua");
doTestDebugResponseCallgraphSerialization(frames);
} catch (IOException e) {
fail(e.getMessage());
}
}
private void doTestDebugResponseCallgraphSerialization(StackFrame[] frames)
throws IOException {
DebugResponseCallgraph responseIn = new DebugResponseCallgraph(frames);
byte[] data = SerializationHelper.serialize(responseIn);
DebugResponseCallgraph responseOut =
(DebugResponseCallgraph) SerializationHelper.deserialize(data);
assertNotNull(responseOut);
StackFrame[] inFrames = responseIn.getCallgraph();
StackFrame[] outFrames = responseOut.getCallgraph();
assertNotNull(outFrames);
assertEquals(inFrames.length, outFrames.length);
for (int i = 0; i < inFrames.length; i++) {
assertEquals(inFrames[i], outFrames[i]);
}
}
}

View File

@@ -0,0 +1,41 @@
package lua.debug;
import junit.framework.TestCase;
public class EnumTypeTest extends TestCase {
public void testDebugSupportStateSerialization() {
try {
DebugSupport.State stateIn = DebugSupport.State.RUNNING;
byte[] data = SerializationHelper.serialize(stateIn);
DebugSupport.State stateOut
= (DebugSupport.State) SerializationHelper.deserialize(data);
assertEquals(stateIn, stateOut);
} catch (Exception e) {
fail(e.getMessage());
}
}
public void testDebugRequestTypeSerialization() {
try {
DebugRequestType type = DebugRequestType.lineBreakpointClear;
byte[] data = SerializationHelper.serialize(type);
DebugRequestType typeOut
= (DebugRequestType) SerializationHelper.deserialize(data);
assertEquals(type, typeOut);
} catch (Exception e) {
fail(e.getMessage());
}
}
public void testDebugEventTypeSerialization() {
try {
DebugEventType type = DebugEventType.error;
byte[] data = SerializationHelper.serialize(type);
DebugEventType typeOut = (DebugEventType) SerializationHelper.deserialize(data);
assertNotNull(typeOut);
assertEquals(type, typeOut);
} catch (Exception e) {
fail(e.getMessage());
}
}
}

View File

@@ -21,29 +21,99 @@
******************************************************************************/ ******************************************************************************/
package lua.debug; package lua.debug;
import java.io.IOException;
import java.net.URL; import java.net.URL;
import junit.framework.TestCase; import junit.framework.TestCase;
import lua.debug.StandardLuaJVM.ParseException;
/** /**
* Sanity test for StandardLuaJVM. * Sanity test for StandardLuaJVM.
*/ */
public class LuaJVMTest extends TestCase { public class LuaJVMTest extends TestCase {
protected void doTestRun(String testName) { public void testCommandLineParse() {
String[] args = new String[2]; // null arguments
args[0] = "-file"; String[] args = null;
URL filePath = getClass().getResource("/"+ testName); StandardLuaJVM vm = new StandardLuaJVM();
if (filePath != null) { try {
args[1] = filePath.getPath(); vm.parse(args);
try { fail("Bad parsing program. Should never reach this line.");
StandardLuaJVM.main(args); } catch (ParseException e) {}
} catch (Exception e) {
e.printStackTrace(); // empty arguments
fail("Test " + testName + " failed due to " + e.getMessage()); args = new String[] {};
} try {
} vm.parse(args);
} fail("Bad parsing program. Should never reach this line.");
} catch (ParseException e) {}
// incomplete arguments
args = new String[] { "-debug" };
try {
vm.parse(args);
fail("Bad parsing program. Should never reach this line.");
} catch (ParseException e) {}
// incomplete arguments
args = new String[] { "-debug", "1046" };
try {
vm.parse(args);
fail("Bad parsing program. Should never reach this line.");
} catch (ParseException e) {}
// missing script name
args = new String[] { "-debug", "1046", "1047"};
try {
vm.parse(args);
fail("Bad parsing program. Should never reach this line.");
} catch (ParseException e) {}
// malformed request port
args = new String[] { "-debug", "104x", "1046", "dummy.lua"};
try {
vm.parse(args);
fail("Bad parsing program. Should never reach this line.");
} catch (ParseException e) {}
// malformed event port
args = new String[] { "-debug", "1046", "104x", "dummy.lua"};
try {
vm.parse(args);
fail("Bad parsing program. Should never reach this line.");
} catch (ParseException e) {}
// event port == request port
args = new String[] { "-debug", "1046", "1046", "dummy.lua"};
try {
vm.parse(args);
fail("Bad parsing program. Should never reach this line.");
} catch (ParseException e) {}
// lua script cannot be found
args = new String[] { "-debug", "1046", "1047", "dummy.lua"};
try {
vm.parse(args);
vm.run();
fail("Should never reach this line.");
} catch (ParseException e) {
fail("Should never reach this line.");
} catch (IOException e) {
//expected
}
// lua script cannot be found
args = new String[] {"dummy.lua"};
try {
vm.parse(args);
vm.run();
fail("Bad parsing program. Should never reach this line.");
} catch (ParseException e) {
fail("Should never reach this line.");
} catch (IOException e) {
//expected
}
}
public void testRun() { public void testRun() {
String[] tests = new String[] { String[] tests = new String[] {
"autoload", "autoload",
@@ -78,4 +148,18 @@ public class LuaJVMTest extends TestCase {
System.out.println(); System.out.println();
} }
} }
protected void doTestRun(String testName) {
String[] args = new String[1];
URL filePath = getClass().getResource("/"+ testName);
if (filePath != null) {
args[0] = filePath.getPath();
try {
StandardLuaJVM.main(args);
} catch (Exception e) {
e.printStackTrace();
fail("Test " + testName + " failed due to " + e.getMessage());
}
}
}
} }

View File

@@ -0,0 +1,19 @@
package lua.debug;
import java.io.IOException;
import junit.framework.TestCase;
public class StackFrameTest extends TestCase {
public void testSerialization() {
try {
StackFrame stackIn = new StackFrame(10, "test.lua");
byte[] data = SerializationHelper.serialize(stackIn);
StackFrame stackOut = (StackFrame) SerializationHelper.deserialize(data);
assertNotNull(stackOut);
assertEquals(stackIn, stackOut);
} catch (IOException e) {
fail(e.getMessage());
}
}
}

View File

@@ -0,0 +1,134 @@
package lua.debug;
import java.io.IOException;
import junit.framework.TestCase;
import lua.Lua;
import lua.value.LBoolean;
import lua.value.LDouble;
import lua.value.LInteger;
import lua.value.LNil;
import lua.value.LString;
import lua.value.LTable;
public class TableVariableTest extends TestCase {
public void testCreate() {
LTable table = new LTable();
table.put("key1", new LString("value1"));
table.put("key2", new LNil());
table.put("key3", LBoolean.TRUE);
table.put("key4", LInteger.valueOf(10));
table.put("key5", new LDouble(0.5));
LTable childTable = new LTable();
childTable.put("childKey1", new LString("childValue1"));
table.put("key6", childTable);
TableVariable tableVariable = new TableVariable(0, "tableVar", Lua.LUA_TTABLE, table);
String[] keys = tableVariable.getKeys();
assertNotNull(keys);
assertEquals(keys.length, 6);
for (int i = 0; i < 6; i++) {
assertTrue(keys[i].startsWith("key"));
}
Object[] values = tableVariable.getValues();
assertNotNull(values);
assertEquals(values.length, 6);
for (int i = 0; i < 6; i++) {
if (values[i] instanceof String) {
assertTrue(values[i].equals("value1") ||
values[i].equals("nil") ||
values[i].equals("true") ||
values[i].equals("10") ||
values[i].equals("0.5"));
} else if (values[i] instanceof TableVariable) {
TableVariable child = (TableVariable) values[i];
String[] childKeys = child.getKeys();
assertNotNull(childKeys);
assertEquals(childKeys.length, 1);
assertEquals(childKeys[0], "childKey1");
Object[] childValues = child.getValues();
assertNotNull(childValues);
assertEquals(childValues.length, 1);
assertEquals(childValues[0], "childValue1");
} else {
fail("bad value type");
}
}
}
public void testSerialization() {
String[] keys = null;
Object[] values = null;
try {
doTestSerialization(0, "name", Lua.LUA_TTABLE, keys, values);
} catch (IOException e) {
fail(e.getMessage());
}
keys = new String[0];
values = new String[0];
try {
doTestSerialization(0, "name", Lua.LUA_TTABLE, keys, values);
} catch (IOException e) {
fail(e.getMessage());
}
keys = new String[] {"key1", "key2"};
values = new String[] {"value1", "value2"};
try {
doTestSerialization(0, "name", Lua.LUA_TTABLE, keys, values);
} catch (IOException e) {
fail(e.getMessage());
}
TableVariable grandchild = new TableVariable(1, "child", Lua.LUA_TTABLE, keys, values);
keys = new String[] {"grandchild1", "grandchild2", "grandchild3"};
values = new Object[] {"value1", "value2", grandchild};
TableVariable child = new TableVariable(1, "child", Lua.LUA_TTABLE, keys, values);
keys = new String[] {"child1", "child2"};
values = new Object[] {"value1", child};
try {
doTestSerialization(0, "name", Lua.LUA_TTABLE, keys, values);
} catch (IOException e) {
fail(e.getMessage());
}
}
protected void doTestSerialization(int index, String name, int type,
String[] keys, Object[] values)
throws IOException {
TableVariable in = new TableVariable(index, name, type, keys, values);
byte[] data = SerializationHelper.serialize(in);
TableVariable out = (TableVariable) SerializationHelper.deserialize(data);
assertTableVariable(in, out);
}
private void assertTableVariable(TableVariable in, TableVariable out) {
assertEquals(in.getIndex(), out.getIndex());
assertEquals(in.getType(), out.getType());
assertEquals(in.getName(), out.getName());
String[] inKeys = in.getKeys();
String[] outKeys = out.getKeys();
assertEquals(inKeys == null ? 0 : inKeys.length, outKeys == null ? 0 : outKeys.length);
for (int i = 0; inKeys != null && i < inKeys.length; i++) {
assertEquals(inKeys[i], outKeys[i]);
}
Object[] inValues = in.getValues();
Object[] outValues = out.getValues();
assertEquals(inValues == null ? 0 : inValues.length, outValues == null ? 0 : outValues.length);
for (int i = 0; inValues != null && i < inValues.length; i++) {
if (inValues[i] instanceof String && outValues[i] instanceof String) {
assertEquals(inValues[i], outValues[i]);
} else if (inValues[i] instanceof TableVariable && outValues[i] instanceof TableVariable) {
assertTableVariable((TableVariable)inValues[i], (TableVariable)outValues[i]);
} else {
fail("bad serialization");
}
}
}
}

View File

@@ -0,0 +1,26 @@
package lua.debug;
import java.io.IOException;
import junit.framework.TestCase;
import lua.Lua;
public class VariableTest extends TestCase {
public void testSerialization() {
doTestSerialization(0, "varName", Lua.LUA_TSTRING, null);
doTestSerialization(0, "varName", Lua.LUA_TSTRING, "varValue");
}
protected void doTestSerialization(int index, String varName, int type, String varValue) {
Variable varIn = new Variable(index, varName, type, varValue);
Variable varOut = null;
try {
byte[] data = SerializationHelper.serialize(varIn);
varOut = (Variable) SerializationHelper.deserialize(data);
} catch (IOException e) {
fail(e.getMessage());
}
assertNotNull(varOut);
assertEquals(varIn, varOut);
}
}