1 /**********************************************************************
2 Copyright (c) 2000, 2002 IBM Corp. and others.
3 All rights reserved. This program and the accompanying materials
4 are made available under the terms of the Common Public License v1.0
5 which accompanies this distribution, and is available at
6 http://www.eclipse.org/legal/cpl-v10.html
9 IBM Corporation - Initial implementation
10 Vicente Fernando - www.alfersoft.com.ar
11 **********************************************************************/
12 package net.sourceforge.phpdt.internal.debug.core.model;
14 import java.util.Arrays;
15 import java.util.Vector;
17 import net.sourceforge.phpdt.internal.debug.core.PHPDBGProxy;
19 import org.eclipse.debug.core.DebugEvent;
20 import org.eclipse.debug.core.DebugException;
21 import org.eclipse.debug.core.DebugPlugin;
22 import org.eclipse.debug.core.ILaunch;
23 import org.eclipse.debug.core.model.IDebugTarget;
24 import org.eclipse.debug.core.model.IRegisterGroup;
25 import org.eclipse.debug.core.model.IStackFrame;
26 import org.eclipse.debug.core.model.IThread;
27 import org.eclipse.debug.core.model.IVariable;
31 * TODO Remove the variables array and use only the varList vector
32 * Have also to change hasVariables
34 public class PHPStackFrame extends PHPDebugElement implements IStackFrame, Comparable{
36 private PHPThread thread; // The thread to which this stackframe belongs
37 private String file; // The file name???
38 private int lineNumber; //
41 private PHPVariable[] variables; // The array of variables TODO: better introduce a vector?
42 private Vector varList = new Vector ();
43 private String description; // The source file name with the full path on target/remote system
44 private boolean fUpToDate; //
55 public PHPStackFrame (PHPThread thread, String file, int line, int index, String desc, int modno) {
58 this.lineNumber = line;
62 this.description = desc;
64 this.fUpToDate = false;
74 public PHPStackFrame (PHPThread thread, String file, int line, int index) {
77 this.lineNumber = line;
81 this.fUpToDate = false;
87 public IThread getThread () {
94 public void setThread (PHPThread thread) {
101 private void setUpToDate (boolean upToDate) {
102 fUpToDate = upToDate;
108 private boolean isUpToDate () {
116 private void resetHasChangedInfo (Vector varList) {
121 for (n = 0; n < varList.size (); n++) { // For every variable in 'DBG list'
122 var = (PHPVariable) varList.get (n); // Get the variable
123 val = (PHPValue) var.getValue (); // Get the variable's value
126 if (val.hasVariables ()) { // Do we have other variables within the value
127 if (!hasRecursion (var)) { // Is this variable (value) branch recursive?
128 resetHasChangedInfo (val.getChildVariables ()); // No, go into branch
132 catch (DebugException e) { // That's, because of the hasVariables method
135 var.setValueChanged (false); // Reset the 'has changed' flag
140 * Go up the tree of PHPVariables
141 * look whether the PHPValue is a reference to a parent PHPValue
143 * TODO Check where this recursion can come from.
144 * Whether this back reference is legal or a bug.
149 * <li> false if the PHPValue is not a child of itself
150 * <li> true if the PHPValue is
153 private boolean hasRecursion (PHPVariable var) {
154 PHPVariable parentVar;
157 val = (PHPValue) var.getValue (); // Get the PHPValue from the current PHPVariable
159 while (var != null) { // As long as we have PHPVariable
160 parentVar = var.getParent (); // Get the parent PHPVariable
162 if (parentVar != null) { // Is there a parent?
163 if (parentVar.getValue ().equals (val)) { // Get the PHPValue for the parent PHPVariable and check
164 // whether it is the same
165 return true; // Return, if we have recursion
172 return false; // No recursion found
176 * This method updates the 'static' variables list.
177 * It does a replication between the 'static' list (the variable list which
178 * is a member of this DBG interface object) and the DBG variable list
179 * (the list of variables which is received from PHP via DBG with the current suspend)
180 * Replication is done in the following way:
182 * <li> It looks for new variables within the DBG variables list and
183 * adds them to the 'static' list.
184 * <li> It looks for changed variables copies the current value to the variable within
185 * the 'static list' and mark these variables as 'hasChanged' (which uses the UI
186 * for showing the variable with a different color).
187 * <li> It looks for variables within the 'static' list, and removes them
188 * from the 'static' list in case the do not appear within the DBG list.
191 * @param varListOld The 'static' list of variables which are to be updated.
192 * @param varListNew The new list of (current) variables from DBG.
194 private void updateVariableList (Vector varListOld, Vector varListNew)
196 PHPVariable varOld; // The variable from the 'static' list
197 PHPVariable varNew; // The variable from the DBG list
198 PHPValue valOld; // The value of the current variable from 'static' list
199 PHPValue valNew; // The value of the current variable from DBG list
200 int n; // Index for the DBG list
201 int o; // Index for the static list
203 // Add the variables (and childs) to the static list if they are new
204 // and update the values of variables which are already existend within
205 // the 'static' list.
207 for (n = 0; n < varListNew.size (); n++) { // For every variable in 'DBG list'
208 varNew = (PHPVariable) varListNew.get (n); // Get the DBG variable
210 for (o = 0; o < varListOld.size (); o++) { // For every variable in static list
211 varOld = (PHPVariable) varListOld.get (o); // Get the static variable
213 if (varNew.getName ().equals (varOld.getName ())) { // Did we found the variable within the 'static' list?
214 valOld = (PHPValue) varOld.getValue (); // Get the value from 'static'
215 valNew = (PHPValue) varNew.getValue (); // Get the value from DBG
218 if (valOld.hasVariables () || // If the 'static' value has child variables
219 valNew.hasVariables ()) { // or if the DBG value has child variables
220 if (!hasRecursion (varOld) &&
221 !hasRecursion (varNew)) { // Both branches should not have a recursion
222 updateVariableList (valOld.getChildVariables (), // Update the variable list for the child variables
223 valNew.getChildVariables ());
226 else if (!valOld.getValueString ().equals (valNew.getValueString ())) { // Has the value changed?
227 valOld.setValueString (valNew.getValueString ()); // Yes, set the 'static' value (variable) to the new value
228 varOld.setValueChanged (true); // and set the 'has changed' flag, so that the variable view
229 // could show the user the changed status with a different
233 // varOld.setValueChanged (false); // Reset the 'has changed' flag
236 catch (DebugException e) { // That's, because of the hasVariables method
239 break; // Found the variable,
243 if (o == varListOld.size ()) { // Did we found the variable within the static list?
244 varListOld.add (varNew); // No, then add the DBG variable to the static list
248 // Look for the variables we can remove from the 'static' list
250 for (o = 0; o < varListOld.size (); o++) { // For every variable in 'static' list
251 varOld = (PHPVariable) varListOld.get (o); // Get the static variable
253 for (n = 0; n < varListNew.size (); n++) { // For all variables in 'DBG' list
254 varNew = (PHPVariable) varListNew.get (n); // Get the variable from the 'DBG' list
256 if (varNew.getName ().equals (varOld.getName ())) { // Did we found the 'static' list variable within the 'DBG' list?
257 break; // Yes we found the variable, then leave the loop
261 if (n == varListNew.size ()) { // Did not find the 'static' list variable within the 'DBG' list?
262 varListOld.remove (o); // then remove the 'static' list variable from list
263 o -= 1; // Adjust the 'static' list index
271 * This function returns the array of PHPVariables for this stackframe
272 * The PHPVariables should not change (newly build up) between two steps
274 * A PHPVariable with the same name but with different object ID is
275 * handled as a new variable.
277 * TODO Remove the intermediate storage array
279 * @return The array of PHPVariables for this stackframe.
281 public IVariable[] getVariables() throws DebugException {
282 PHPVariable[] variablesNew; // The intermediate storage of the variable array we get from DBG proxy
284 //variablesNew = this.getPHPDBGProxy ().readVariables (this); // Get the variable array from DBG proxy
285 //variables = variablesNew; // Store the array the stackframes member variable
287 if (!isUpToDate ()) {
288 resetHasChangedInfo (varList);
289 updateVariableList (varList, this.getPHPDBGProxy ().readVariables (this));
292 variables = (PHPVariable[]) varList.toArray (new PHPVariable[varList.size ()]);
293 Arrays.sort(variables, new PHPVariableComparator());
296 return variables; // Give the array back to user interface
302 private PHPVariable findVariable (Vector varList, String varname) {
303 PHPVariable variable;
307 for (i = 0; i < varList.size (); i++) { // For all variables
308 variable = (PHPVariable) varList.get (i); // Get the variable
309 value = (PHPValue) variable.getValue (); // Get the value of the variable
312 if (value.hasVariables ()) { // Does the variable/value have children
313 if (!hasRecursion (variable)) { // Don't follow recursive variable/values
314 variable = findVariable (value.getChildVariables (), varname);
316 if (variable != null) {
321 else if ((variable.getName ()).equals (varname)) { //
325 catch (DebugException e) { // That's, because of the hasVariables method
333 * This method is called from the UI (e.g. from PHPDebugHover
334 * to find the variable the mouse is pointing to)
336 * @param s The variable name we are looking for.
339 public IVariable findVariable (String s) throws DebugException {
340 if (!isUpToDate ()) {
341 resetHasChangedInfo (varList);
342 updateVariableList (varList, this.getPHPDBGProxy ().readVariables (this));
345 variables = (PHPVariable[]) varList.toArray (new PHPVariable[varList.size ()]);
348 return (findVariable (varList, s)); // Prefix the variable name with $
354 public boolean hasVariables () throws DebugException {
355 return (varList.size () > 0);
358 public int getLineNumber() {
362 public void setLineNumber(int line) {
366 public int getCharStart() throws DebugException {
371 public int getCharEnd() throws DebugException {
376 public String getName() {
377 StringBuffer name = new StringBuffer();
379 if (!this.getDescription().equals ("")) {
380 name.append (this.getDescription ());
383 name.append (this.getFileName ());
386 name.append (" [line ");
387 name.append (this.getLineNumber ());
390 return name.toString();
393 public String getFileName() {
397 public void setDescription(String desc) {
398 this.description= desc;
401 public String getDescription() {
402 return this.description;
405 public IRegisterGroup[] getRegisterGroups() throws DebugException {
409 public boolean hasRegisterGroups() throws DebugException {
413 public String getModelIdentifier() {
414 return this.getThread().getModelIdentifier();
417 public IDebugTarget getDebugTarget() {
418 return this.getThread().getDebugTarget();
421 public ILaunch getLaunch() {
422 return this.getDebugTarget().getLaunch();
425 public boolean canStepInto() {
429 public boolean canStepOver() {
433 public boolean canStepReturn() {
437 public boolean isStepping() {
444 public void stepInto () throws DebugException {
449 thread.prepareForResume (DebugEvent.STEP_INTO); // Don't know why, but this is necessary
450 this.getPHPDBGProxy ().readStepIntoEnd (PHPStackFrame.this);
452 ev = new DebugEvent (this.getThread (), DebugEvent.RESUME, DebugEvent.STEP_INTO);
453 DebugPlugin.getDefault().fireDebugEventSet (new DebugEvent[] { ev });
459 public void stepOver () throws DebugException {
464 thread.prepareForResume (DebugEvent.STEP_OVER);
465 this.getPHPDBGProxy ().readStepOverEnd (PHPStackFrame.this) ;
467 ev = new DebugEvent (this.getThread (), DebugEvent.RESUME, DebugEvent.STEP_OVER);
468 DebugPlugin.getDefault ().fireDebugEventSet (new DebugEvent[] { ev });
474 public void stepReturn () throws DebugException {
479 thread.prepareForResume (DebugEvent.STEP_RETURN);
480 this.getPHPDBGProxy ().readStepReturnEnd (PHPStackFrame.this) ;
482 ev = new DebugEvent (this.getThread (), DebugEvent.RESUME, DebugEvent.STEP_RETURN);
483 DebugPlugin.getDefault ().fireDebugEventSet (new DebugEvent[] { ev });
487 public boolean canResume() {
488 return this.getThread().canResume();
491 public boolean canSuspend() {
492 return this.getThread().canSuspend();
495 public boolean isSuspended() {
496 return this.getThread().isSuspended();
499 public void resume() throws DebugException {
501 this.getThread().resume();
504 public void suspend() throws DebugException {
507 public boolean canTerminate() {
508 return this.getThread().canTerminate();
511 public boolean isTerminated() {
512 return this.getThread().isTerminated();
515 public void terminate() throws DebugException {
516 getPHPDBGProxy().stop();
519 public int getIndex() {
523 public void setIndex (int index) {
527 public PHPDBGProxy getPHPDBGProxy() {
528 PHPDebugTarget DebugTarget;
530 DebugTarget = (PHPDebugTarget) thread.getDebugTarget ();
532 return DebugTarget.getPHPDBGProxy ();
535 public void setFile(String file) {
539 public int getModNo() {
544 * This function is needed when sorting the stackframes by their index numbers.
546 * @param obj The stackframe which this one is compared to.
549 * <li> -1 if the index of this stackframe is less.
550 * <li> 0 if the index of both stackfream is equal (should no happen).
551 * <li> 1 if the index of this stackfram is greater.
554 public int compareTo (Object obj)
556 if (index < ((PHPStackFrame) obj).getIndex ()) {
559 else if (index > ((PHPStackFrame) obj).getIndex ()) {