Web-разработка, иностранные языки, Eclipse и разные разности

Zygo Profile

Санскрит - словоформы

Verbos Irregulares

4. Пошаговое прохождение, приостановка и другие действия

03.11.2015

В прошлой части руководства мы создали базовую структуру нашего отладчика. В этой части мы поработаем над UI интеграцией.

Когда отладчик запущен, Эклипс предоставляет различные действия на панели инструментов в зависимости того, что выбрано в Debug view. Существует четыре различных типа действий:

  • Terminate (завершение)
  • Suspend/Resume (приостановка/возобновление)
  • Disconnect (отключение)
  • Stepping (пошаговое выполнение)

Для каждой из этих групп существуют интерфейсы (ITerminate, ISuspendResume, IDisconnect and IStep). Когда выбранный элемент осуществляет один из приведенных интерфейсов, становятся доступны соответствующие действия на панели инструментов. Активация элемента обрабатывается такими методами интерфейса как  canDisconnect(), canResume()..

В этом руководстве мы будем шаг за шагом применять все эти возможности.

Шаг 1. Приостановка/возобновление


Наш отладчик очень простой. У нас нет множества потоков, поэтому функционал приостановки/возобновления один и тот же, что для DebugTarget, Thread или StackFrame (мы вернемся к этому в следующих частях).

Поскольку приостановка/возобновление уже реализованы, мы всего лишь внесем изменения в наш код и переместим ISuspendResume в наш базовый класс TextDebugElement.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.codeandme.textinterpreter.debugger.model;  
  
public abstract class TextDebugElement extends DebugElement implements ISuspendResume, IDisconnect, ITerminate, IStep {  
  
 // FIXME for full source code see http://codeandme.googlecode.com/svn/trunk/blog/debugger/04/com.codeandme.textinterpreter.debugger/src/com/codeandme/textinterpreter/debugger/model/TextDebugElement.java  
  
 public enum State {  
  NOT_STARTED, SUSPENDED, RESUMED, TERMINATED, STEPPING  
 };  
  
 private State mState = State.NOT_STARTED;  
  
 protected void setState(State state) {  
  // only the DebugTarget saves the correct state.  
  ((TextDebugElement) getDebugTarget()).mState = state;  
 }  
  
 protected State getState() {  
  return ((TextDebugElement) getDebugTarget()).mState;  
 }  
  
 // ************************************************************  
 // ISuspendResume  
 // ************************************************************  
  
 @Override  
 public boolean canResume() {  
  return isSuspended();  
 }  
  
 @Override  
 public boolean canSuspend() {  
  // we cannot interrupt our debugger once it is running  
  return false;  
 }  
  
 @Override  
 public boolean isSuspended() {  
  return (getState() == State.SUSPENDED);  
 }  
  
 @Override  
 public void resume() {  
  // resume request from eclipse  
  
  // send resume request to debugger  
  getDebugTarget().fireModelEvent(new ResumeRequest(ResumeRequest.CONTINUE));  
 }  
  
 @Override  
 public void suspend() throws DebugException {  
  throw new DebugException(new Status(IStatus.ERROR, "com.codeandme.textinterpreter.debugger", "suspend() not supported"));  
 }  
}  

Любое действие, которое омжет быть вызвано из элемента панели инструментов, содержит метод canSomething(), который содержит проверку, необходимую для активации кнопок (строки 26-35). Что касается возобновления, это всего лишь вопрос посылки отладчику запроса на возобновление ResumeRequest.

Перемещение в базовый класс позволяет любой из наших реализаций модели использовать возобновление. Кроме того, мы можем уничтожить некоторый устаревший код из TextDebugTarget и TextThread.

Шаг 2. Поддержка реализации завершения и отключения.


Мы вновь добавляем функционал в базовый класс.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.codeandme.textinterpreter.debugger.model;  
  
public abstract class TextDebugElement extends DebugElement implements ISuspendResume, IDisconnect, ITerminate, IStep {  
  
 // FIXME for full source code see http://codeandme.googlecode.com/svn/trunk/blog/debugger/04/com.codeandme.textinterpreter.debugger/src/com/codeandme/textinterpreter/debugger/model/TextDebugElement.java  
  
 // ************************************************************  
 // IDisconnect  
 // ************************************************************  
  
 @Override  
 public boolean canDisconnect() {  
  return canTerminate();  
 }  
  
 @Override  
 public void disconnect() {  
  // disconnect request from eclipse  
  
  // send disconnect request to debugger  
  getDebugTarget().fireModelEvent(new DisconnectRequest());  
  
  // debugger is detached, simulate terminate event  
  getDebugTarget().handleEvent(new TerminatedEvent());  
 }  
  
 @Override  
 public boolean isDisconnected() {  
  return isTerminated();  
 }  
  
 // ************************************************************  
 // ITerminate  
 // ************************************************************  
  
 @Override  
 public boolean canTerminate() {  
  return !isTerminated();  
 }  
  
 @Override  
 public boolean isTerminated() {  
  return (getState() == State.TERMINATED);  
 }  
  
 @Override  
 public void terminate() {  
  // terminate request from eclipse  
  
  // send terminate request to debugger  
  getDebugTarget().fireModelEvent(new TerminateRequest());  
 }  
}  

В то время как terminate() мгновенно остановит отладочную сессию (вместе с интерпретатором), disconnect() всего лишь отключит отладчик Эклипса, но возобновит работу интерпретатора. По этой причине нам необходимо расширить событие TextDebugger.handleEvent().


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
@Override  
public void handleEvent(final IDebugEvent event) {  
 System.out.println("Debugger.handleEvent() " + event);  
  
 if (event instanceof ResumeRequest) {  
  mIsStepping = (((ResumeRequest) event).getType() == ResumeRequest.STEP_OVER);  
  mInterpreter.resume();  
 }  
  
 else if (event instanceof TerminateRequest)  
  mInterpreter.terminate();  
  
 else if (event instanceof DisconnectRequest) {  
  mInterpreter.setDebugger(null);  
  mInterpreter.resume();  
 }  
}  

Шаг 3. Поддержка пошагового выполнения.


Сейчас перейдем к самому интересному: реализации пошагового выполнения. Наш вымышленный язык настолько прост, что он не поддерживает step into ни step return. Таким образом, остается только step over. Как и ранее, мы реализуем функционал базового класса.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.codeandme.textinterpreter.debugger.model;  
  
public abstract class TextDebugElement extends DebugElement implements ISuspendResume, IDisconnect, ITerminate, IStep {  
  
 // FIXME for full source code see http://codeandme.googlecode.com/svn/trunk/blog/debugger/04/com.codeandme.textinterpreter.debugger/src/com/codeandme/textinterpreter/debugger/model/TextDebugElement.java  
  
 // ************************************************************  
 // IStep  
 // ************************************************************  
  
 @Override  
 public boolean canStepInto() {  
  return false;  
 }  
  
 @Override  
 public boolean canStepOver() {  
  return isSuspended();  
 }  
  
 @Override  
 public boolean canStepReturn() {  
  return false;  
 }  
  
 @Override  
 public boolean isStepping() {  
  return (getState() == State.STEPPING);  
 }  
  
 @Override  
 public void stepInto() throws DebugException {  
  throw new DebugException(new Status(IStatus.ERROR, "com.codeandme.textinterpreter.debugger", "stepInto() not supported"));  
 }  
  
 @Override  
 public void stepOver() {  
  // stepOver request from eclipse  
  
  // send stepOver request to debugger  
  getDebugTarget().fireModelEvent(new ResumeRequest(ResumeRequest.STEP_OVER));  
 }  
  
 @Override  
 public void stepReturn() throws DebugException {  
  throw new DebugException(new Status(IStatus.ERROR, "com.codeandme.textinterpreter.debugger", "stepReturn() not supported"));  
 }  
}  

Необходимо упомянуть одну вещь, касаемую пошагового выполнения: отладочный фреймворк различает запросы на возобновление (resume request) и пошаговые запросы (step requests). Поэтому мы добавляем новое состояние дебаггера: STEPPING. Классу TextDebugger необходимо продолжать отслеживать тип возобновления (continue, step over, step into, step return) и отправлять соответствующие события обратно DebugTarget:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.codeandme.textinterpreter.debugger;  
  
public class TextDebugger implements IDebugger, IEventProcessor {  
  
 // FIXME for full source code see http://codeandme.googlecode.com/svn/trunk/blog/debugger/04/com.codeandme.textinterpreter.debugger/src/com/codeandme/textinterpreter/debugger/TextDebugger.java  
  
 private boolean mIsStepping = false;  
  
 @Override  
 public void resumed() {  
  fireEvent(new ResumedEvent(mIsStepping ? ResumedEvent.STEPPING : ResumedEvent.CONTINUE));  
 }  
  
 @Override  
 public boolean isBreakpoint(final int lineNumber) {  
  return mIsStepping;  
 }  
  
 @Override  
 public void handleEvent(final IDebugEvent event) {  
  System.out.println("Debugger.handleEvent() " + event);  
  
  if (event instanceof ResumeRequest) {  
   mIsStepping = (((ResumeRequest) event).getType() == ResumeRequest.STEP_OVER);  
   mInterpreter.resume();  
  }  
 }  
}  

Классу TextDebugTarget в итоге необходимо запустить соответствующее событие для отладочного фреймворка:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.codeandme.textinterpreter.debugger.model;  
  
public class TextDebugTarget extends TextDebugElement implements IDebugTarget, IEventProcessor {  
  
 // FIXME for full source code see http://codeandme.googlecode.com/svn/trunk/blog/debugger/04/com.codeandme.textinterpreter.debugger/src/com/codeandme/textinterpreter/debugger/model/TextDebugTarget.java  
  
 @Override  
 public void handleEvent(final IDebugEvent event) {  
  
  if (!isDisconnected()) {  
   System.out.println("Target.handleEvent() " + event);  
  
   if (event instanceof ResumedEvent) {  
    if (((ResumedEvent) event).getType() == ResumedEvent.STEPPING) {  
     setState(State.STEPPING);  
     fireResumeEvent(DebugEvent.STEP_OVER);  
  
    } else {  
     setState(State.RESUMED);  
     fireResumeEvent(DebugEvent.UNSPECIFIED);  
    }  
   }  
  }  
 }  
}  

В данный момент вы уже можете запустить отладчик в пошаговом режиме. Чтобы проверить результаты, посмотрите системный вывод в консоли.
Облако тегов
Меню
Архив
© Psytronica.ru. Блог существа SherZa. 2015-2017 Наверх