Commits

Anonymous committed 68b02dd

- Continuing refactoring swank interface to decouple it from rest of the plugin.

Comments (0)

Files changed (11)

src/org/lispdev/swank/DebugInfo.java

+package org.lispdev.swank;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The structure that is initialized when {@link SwankEvent#DEBUG} is received
+ * from {@link SwankRunnable#result} using {@link LispImplementation#getDebugInfo}
+ */
+public class DebugInfo
+{
+  public final String thread;
+  public final int level;
+  /**
+   * the condition to debug
+   */
+  public final String condition;
+  public final List<SwankDebugRestart> restarts =
+    new ArrayList<SwankDebugRestart>();
+  public final List<String> frames = new ArrayList<String>();
+
+  public DebugInfo(String thread, int lvl, String condition)
+  {
+    this.thread = thread;
+    level = lvl;
+    this.condition = condition;
+  }
+
+  public void addRestart(String name, String description)
+  {
+    restarts.add(new SwankDebugRestart(capitalizeString(name), description));
+  }
+
+  private static String capitalizeString(String string)
+  {
+    char[] chars = string.toLowerCase().toCharArray();
+    boolean found = false;
+    for(int i = 0; i < chars.length; i++)
+    {
+      if( !found && Character.isLetter(chars[i]) )
+      {
+        chars[i] = Character.toUpperCase(chars[i]);
+        found = true;
+      }
+      else if( Character.isWhitespace(chars[i]) || chars[i] == '-' )
+      { // You can add other chars here
+        found = false;
+      }
+    }
+    return String.valueOf(chars);
+  }
+
+  public void addFrame(String frame)
+  {
+    frames.add(frame);
+  }
+
+  public static class SwankDebugRestart
+  {
+    public final String name;
+    public final String description;
+
+    public SwankDebugRestart(String name, String description)
+    {
+      this.name = name;
+      this.description = description;
+    }
+  }
+
+  @Override
+  public int hashCode()
+  {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + ((condition == null) ? 0 : condition.hashCode());
+    result = prime * result + level;
+    result = prime * result + ((thread == null) ? 0 : thread.hashCode());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object obj)
+  {
+    if( this == obj ) return true;
+    if( obj == null ) return false;
+    if( getClass() != obj.getClass() ) return false;
+    DebugInfo other = (DebugInfo)obj;
+    if( condition == null )
+    {
+      if( other.condition != null ) return false;
+    }
+    else if( !condition.equals(other.condition) ) return false;
+    if( level != other.level ) return false;
+    if( thread == null )
+    {
+      if( other.thread != null ) return false;
+    }
+    else if( !thread.equals(other.thread) ) return false;
+    return true;
+  }
+}

src/org/lispdev/swank/ISwank.java

    * @param info debug info obtained at debug start
    * @param callBack leave it null if want to process events through listeners
    */
-  void sendDebug(int commandNum, SwankDebugInfo info, SwankRunnable callBack);
+  void sendDebug(int commandNum, DebugInfo info, SwankRunnable callBack);
   void sendListThreads(SwankRunnable callBack);
 
   public LispVariable[] getFrameLocals(int frameNum, String threadId,

src/org/lispdev/swank/LispImplementation.java

   }
 
   /**
-   * Converts debugInfo node to corresponding structure.
+   * Converts debugInfo node (the result of {@link SwankEvent#DEBUG})
+   * to the corresponding structure.
    * Debug info node is assumed to be of the following form:
    * (:debug 0 1 ("break" " [condition]") (("RESTART1" "restart 1")
    *   ("RESTART2" "restart 2")) ((0 "(frame 0)") (1 "frame 1")))
    */
-  public SwankDebugInfo getDebugInfo(LispNode debugInfo)
+  public DebugInfo getDebugInfo(LispNode debugInfo)
   {
     if( debugInfo == null || !debugInfo.get(0).value.equals(":debug")
         || debugInfo.getParamsCount() < 6
           String.valueOf(debugInfo));
       return null;
     }
-    SwankDebugInfo res = new SwankDebugInfo(debugInfo.get(1).value,
+    DebugInfo res = new DebugInfo(debugInfo.get(1).value,
         debugInfo.get(2).asInt(),
         debugInfo.get(3).get(0) + "\n" + debugInfo.get(3).get(1));
     if( res.condition == null || res.thread == null )
     return res;
   }
 
+  /**
+   * Converts {@link LispNode} n, which is result of
+   * @param target
+   * @param n
+   * @return
+   */
   public LispVariable[] getLispVariables(LispDebugTarget target, LispNode n)
   {
     if( n == null || n.getParamsCount() < 1 )

src/org/lispdev/swank/LispThread.java

 public class LispThread extends LispDebugElement implements IThread
 {
   private boolean suspended;
-  private SwankDebugInfo debugInfo = null;
+  private DebugInfo debugInfo = null;
 
   public LispThread(LispDebugTarget target)
   {
     return null;
   }
 
-  public SwankDebugInfo getDebugInfo()
+  public DebugInfo getDebugInfo()
   {
     if( isSuspended() )
     {
   {
   }
 
-  public void setSuspended(SwankDebugInfo info)
+  public void setSuspended(DebugInfo info)
   {
     debugInfo = info;
     suspended = (info != null);

src/org/lispdev/swank/ReadStringInfo.java

+package org.lispdev.swank;
+
+/**
+ * The structure is initialized when {@link SwankEvent#READ_STRING} is received
+ * by its listeners from {@link SwankRunnable#result} using
+ */
+public class ReadStringInfo
+{
+
+}

src/org/lispdev/swank/SwankDebugInfo.java

-package org.lispdev.swank;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class SwankDebugInfo
-{
-  public final String thread;
-  public final int level;
-  /**
-   * the condition to debug
-   */
-  public final String condition;
-  public final List<SwankDebugRestart> restarts =
-    new ArrayList<SwankDebugRestart>();
-  public final List<String> frames = new ArrayList<String>();
-
-  public SwankDebugInfo(String thread, int lvl, String condition)
-  {
-    this.thread = thread;
-    level = lvl;
-    this.condition = condition;
-  }
-
-  public void addRestart(String name, String description)
-  {
-    restarts.add(new SwankDebugRestart(capitalizeString(name), description));
-  }
-
-  private static String capitalizeString(String string)
-  {
-    char[] chars = string.toLowerCase().toCharArray();
-    boolean found = false;
-    for(int i = 0; i < chars.length; i++)
-    {
-      if( !found && Character.isLetter(chars[i]) )
-      {
-        chars[i] = Character.toUpperCase(chars[i]);
-        found = true;
-      }
-      else if( Character.isWhitespace(chars[i]) || chars[i] == '-' )
-      { // You can add other chars here
-        found = false;
-      }
-    }
-    return String.valueOf(chars);
-  }
-
-  public void addFrame(String frame)
-  {
-    frames.add(frame);
-  }
-
-  public static class SwankDebugRestart
-  {
-    public final String name;
-    public final String description;
-
-    public SwankDebugRestart(String name, String description)
-    {
-      this.name = name;
-      this.description = description;
-    }
-  }
-
-  @Override
-  public int hashCode()
-  {
-    final int prime = 31;
-    int result = 1;
-    result = prime * result + ((condition == null) ? 0 : condition.hashCode());
-    result = prime * result + level;
-    result = prime * result + ((thread == null) ? 0 : thread.hashCode());
-    return result;
-  }
-
-  @Override
-  public boolean equals(Object obj)
-  {
-    if( this == obj ) return true;
-    if( obj == null ) return false;
-    if( getClass() != obj.getClass() ) return false;
-    SwankDebugInfo other = (SwankDebugInfo)obj;
-    if( condition == null )
-    {
-      if( other.condition != null ) return false;
-    }
-    else if( !condition.equals(other.condition) ) return false;
-    if( level != other.level ) return false;
-    if( thread == null )
-    {
-      if( other.thread != null ) return false;
-    }
-    else if( !thread.equals(other.thread) ) return false;
-    return true;
-  }
-}

src/org/lispdev/swank/SwankDebugRunnable.java

+package org.lispdev.swank;
+
+import org.eclipse.core.runtime.Assert;
+
+public abstract class SwankDebugRunnable extends SwankRunnable
+{
+  final private LispImplementation implem;
+
+  public SwankDebugRunnable(LispImplementation implementation)
+  {
+    Assert.isNotNull(implementation);
+    implem = implementation;
+  }
+
+  public DebugInfo getInfo()
+  {
+    if( result == null )
+    {
+      return null;
+    }
+    return implem.getDebugInfo(result);
+  }
+}

src/org/lispdev/swank/SwankInterface.java

   }
 
   @Override
-  public synchronized void sendDebug(int commandNum, SwankDebugInfo info,
+  public synchronized void sendDebug(int commandNum, DebugInfo info,
       SwankRunnable callBack)
   {
     String msg =

src/org/lispdev/swank/SwankInterfaceCore.java

 import java.util.List;
 import java.util.StringTokenizer;
 
+import org.eclipse.core.runtime.Assert;
 import org.eclipse.core.runtime.ListenerList;
 
 public class SwankInterfaceCore
 
   synchronized public void addListener(SwankEvent e, SwankRunnable r)
   {
+    switch(e)
+    {
+      case DEBUG:
+        Assert.isLegal(r instanceof SwankDebugRunnable);
+        break;
+      default:
+    }
     getListeners(e).add(r);
   }
 
     Object r = jobs.get(jobNum);
     if( r != null )
     {
-      SwankRunnable runnable = (SwankRunnable)r;
-      runnable.event = SwankEvent.DEFAULT;
-      runnable.result = reply;
-      runnableDriver.asyncExec(runnable);
+      SwankRunner runner =
+        new SwankRunner(reply, SwankEvent.DEFAULT, (SwankRunnable)r);
+      runnableDriver.asyncExec(runner);
       jobs.remove(jobNum);
     }
     else
     }
     for(Object o : ll.getListeners())
     {
-      SwankRunnable runnable = ((SwankRunnable)o).clone();
-      runnable.result = result;
-      runnable.event = event;
-      runnableDriver.asyncExec(runnable);
+      SwankRunner runner = new SwankRunner(result, event, (SwankRunnable)o);
+      runnableDriver.asyncExec(runner);
+    }
+  }
+
+  private static class SwankRunner implements Runnable
+  {
+    private final LispNode result;
+    private final SwankRunnable runnable;
+    private final SwankEvent event;
+
+    public SwankRunner(LispNode result, SwankEvent event,
+        SwankRunnable runnable)
+    {
+      this.result = result;
+      this.runnable = runnable;
+      this.event = event;
+    }
+
+    @Override
+    public void run()
+    {
+      synchronized( runnable )
+      {
+        runnable.setResult(result);
+        runnable.setEvent(event);
+        runnable.run();
+      }
     }
   }
 

src/org/lispdev/swank/SwankInterfaceTest.java

         "    ))", 1000);
     assertEquals("G", res);
 
-    final SwankDebugInfo[] infos = new SwankDebugInfo[2];
+    final DebugInfo[] infos = new DebugInfo[2];
 
-    final SwankRunnable debugInfo = new SwankRunnable(){
+    final LispImplementation implem = si.getLispImplementation();
+    final SwankDebugRunnable debugInfo = new SwankDebugRunnable(implem){
       @Override
       public void run()
       {
-        infos[0] = si.getLispImplementation().getDebugInfo(result);
+        infos[0] = getInfo();
       }
     };
-    final SwankRunnable debugInfo1 = new SwankRunnable(){
+    final SwankDebugRunnable debugInfo1 = new SwankDebugRunnable(implem){
       @Override
       public void run()
       {
-        infos[1] = si.getLispImplementation().getDebugInfo(result);
+        infos[1] = getInfo();
       }
     };
     final SwankRunnable debugStart = new SwankRunnable(){
   @Test
   public void test_sendInterrupt()
   {
-    final SwankRunnable debugInfo = new SwankRunnable(){
-      @Override
-      public void run()
-      {
-        synchronized(this)
-        {
-          this.notifyAll();
-        }
-      }
-    };
+    final SwankDebugRunnable debugInfo =
+        new SwankDebugRunnable(si.getLispImplementation()){
+          @Override
+          public void run()
+          {
+            synchronized(this)
+            {
+              this.notifyAll();
+            }
+          }
+        };
     si.swank.addListener(SwankEvent.DEBUG, debugInfo);
     try
     {
     catch(Exception e)
     {}
     si.swank.removeListener(debugInfo);
-    SwankDebugInfo info =
-      si.getLispImplementation().getDebugInfo(debugInfo.result);
+    DebugInfo info = debugInfo.getInfo();
 
     assertEquals("`Interrupt from Emacs`\n" +
     		"`   [Condition of type SIMPLE-ERROR]`", info.condition);
       e.printStackTrace();
     } // catch
 
-    final SwankRunnable debugInfo = new SwankRunnable(){
-      @Override
-      public void run()
-      {}
-    };
+    final SwankDebugRunnable debugInfo =
+      new SwankDebugRunnable(si.getLispImplementation()){
+        @Override
+        public void run()
+        {}
+      };
     final SwankRunnable debugStart = new SwankRunnable(){
       @Override
       public void run()
           if( !started.get() )
           {
             started.set(true);
-            SwankDebugInfo info =
-              si.getLispImplementation().getDebugInfo(debugInfo.result);
+            DebugInfo info = debugInfo.getInfo();
             si.sendInspectFrameLocal(info.thread, "1", "0", callBack);
           }
         }
       }
     }
     assertEquals("F", callBack.getReturn().value);
-    final SwankRunnable debug = new SwankRunnable(){
+    final SwankDebugRunnable debug = new SwankDebugRunnable(si.getLispImplementation()){
       @Override
       public void run()
       {
       e.printStackTrace();
     } // catch
 
-    final SwankRunnable debugInfo = new SwankRunnable(){
+    final SwankDebugRunnable debugInfo = new SwankDebugRunnable(si.getLispImplementation()){
       @Override
       public void run()
       {}
           if( !started.get() )
           {
             started.set(true);
-            SwankDebugInfo info =
-              si.getLispImplementation().getDebugInfo(debugInfo.result);
+            DebugInfo info = debugInfo.getInfo();
             si.sendGetFrameSourceLocation(frame, info.thread, callBack);
           }
         }
   @Test
   public void test_sendGetFrameLocals()
   {
-    final SwankRunnable debugInfo = new SwankRunnable(){
+    final SwankDebugRunnable debugInfo = new SwankDebugRunnable(si.getLispImplementation()){
       @Override
       public void run()
       {}
     {
       e.printStackTrace();
     } // catch
-    SwankDebugInfo info =
-      si.getLispImplementation().getDebugInfo(debugInfo.result);
+    DebugInfo info = debugInfo.getInfo();
     LispVariable[] xx = si.getFrameLocals(1, info.thread, null);
     si.swank.removeListener(debugStart);
     si.swank.removeListener(debugInfo);
       public void run()
       {}
     };
-    final SwankRunnable debugInfo = new SwankRunnable(){
+    final SwankDebugRunnable debugInfo = new SwankDebugRunnable(si.getLispImplementation()){
       @Override
       public void run()
       {}
       public void run()
       {}
     };
-    final SwankRunnable debugInfo = new SwankRunnable(){
+    final SwankDebugRunnable debugInfo = new SwankDebugRunnable(si.getLispImplementation()){
       @Override
       public void run()
       {}
       @Override
       public void run()
       {
-        SwankDebugInfo info =
-          si.getLispImplementation().getDebugInfo(debugInfo.result);
+        DebugInfo info = debugInfo.getInfo();
         si.sendQuitDebug(callBack, info.thread);
       }
     };
       public void run()
       {}
     };
-    final SwankRunnable debugInfo = new SwankRunnable(){
+    final SwankDebugRunnable debugInfo = new SwankDebugRunnable(si.getLispImplementation()){
       @Override
       public void run()
       {}
       @Override
       public void run()
       {
-        SwankDebugInfo info =
-          si.getLispImplementation().getDebugInfo(debugInfo.result);
+        DebugInfo info = debugInfo.getInfo();
         si.sendDebug(1, info, callBack);
       }
     };
   @Test
   public void test_StartDebug()
   {
-    SwankRunnable callBack = new SwankRunnable(){
+    SwankDebugRunnable callBack = new SwankDebugRunnable(si.getLispImplementation()){
 
       @Override
       public void run()

src/org/lispdev/swank/SwankRunnable.java

 
 /**
  * Commands sent to Swank are associated with an instance of some descendant of
- * this class. The result of that command will be stuck in to the result member
- * of the class, and then SwankInterface will <i>attempt</i> to clone the
- * SwankRunnable via the clone method. It should be noted that this tends to
- * fail with anonymous classes, so don't use those where certain threading
- * issues are a concern. The SwankRunnable will then be run in thread of
- * IRunnableDriver. When runnable driver uses
+ * this class. The run memeber will be run in thread of IRunnableDriver.
+ * Right before run is called the SwankRunnable instance is locked and
+ * result and event are set for the duration of run.
+ * When runnable driver uses
  * Display.getDefault().asyncExec(runnable) to call this runnable we avoid the
  * many multithreading issues.
  *
  */
 public abstract class SwankRunnable implements Runnable
 {
-  public LispNode result;
-  public SwankEvent event;
+  protected LispNode result;
+  protected SwankEvent event;
 
+  public void setResult(LispNode result)
+  {
+    this.result = result;
+  }
+
+  public void setEvent(SwankEvent event)
+  {
+    this.event = event;
+  }
+
+  /**
+   * Use this only for eval swankrunnable
+   */
+  @Deprecated
   protected LispNode getReturn()
   {
     return result.getf(":return").getf(":ok");
   }
 
   @Override
-  public SwankRunnable clone()
-  {
-    SwankRunnable ret;
-    try
-    {
-      ret = this.getClass().newInstance();
-      ret.result = result;
-
-      return ret;
-    }
-    catch(InstantiationException e)
-    {}
-    catch(IllegalAccessException e)
-    {}
-
-    return this;
-  }
-
-  @Override
   public String toString()
   {
     return "SwankRunnable [event=" + event + ", result=" + result + "]";