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.Vector;
16 import net.sourceforge.phpdt.internal.debug.core.PHPDBGProxy;
18 import org.eclipse.debug.core.DebugEvent;
19 import org.eclipse.debug.core.DebugException;
20 import org.eclipse.debug.core.DebugPlugin;
21 import org.eclipse.debug.core.ILaunch;
22 import org.eclipse.debug.core.model.IDebugTarget;
23 import org.eclipse.debug.core.model.IRegisterGroup;
24 import org.eclipse.debug.core.model.IStackFrame;
25 import org.eclipse.debug.core.model.IThread;
26 import org.eclipse.debug.core.model.IVariable;
30 * TODO Remove the variables array and use only the varList vector
31 * Have also to change hasVariables
33 public class PHPStackFrame extends PHPDebugElement implements IStackFrame, Comparable{
35 private PHPThread thread; // The thread to which this stackframe belongs
36 private String file; // The file name???
37 private int lineNumber; //
40 private PHPVariable[] variables; // The array of variables TODO: better introduce a vector?
41 private Vector varList = new Vector ();
42 private String description; // The source file name with the full path on target/remote system
43 private boolean fUpToDate; //
54 public PHPStackFrame (PHPThread thread, String file, int line, int index, String desc, int modno) {
57 this.lineNumber = line;
61 this.description = desc;
63 this.fUpToDate = false;
73 public PHPStackFrame (PHPThread thread, String file, int line, int index) {
76 this.lineNumber = line;
80 this.fUpToDate = false;
86 public IThread getThread () {
93 public void setThread (PHPThread thread) {
100 private void setUpToDate (boolean upToDate) {
101 fUpToDate = upToDate;
107 private boolean isUpToDate () {
115 private void resetHasChangedInfo (Vector varList) {
120 for (n = 0; n < varList.size (); n++) { // For every variable in 'DBG list'
121 var = (PHPVariable) varList.get (n); // Get the variable
122 val = (PHPValue) var.getValue (); // Get the variable's value
125 if (val.hasVariables ()) { // Do we have other variables within the value
126 if (!hasRecursion (var)) { // Is this variable (value) branch recursive?
127 resetHasChangedInfo (val.getChildVariables ()); // No, go into branch
131 catch (DebugException e) { // That's, because of the hasVariables method
134 var.setValueChanged (false); // Reset the 'has changed' flag
139 * Go up the tree of PHPVariables
140 * look whether the PHPValue is a reference to a parent PHPValue
142 * TODO Check where this recursion can come from.
143 * Whether this back reference is legal or a bug.
148 * <li> false if the PHPValue is not a child of itself
149 * <li> true if the PHPValue is
152 private boolean hasRecursion (PHPVariable var) {
153 PHPVariable parentVar;
156 val = (PHPValue) var.getValue (); // Get the PHPValue from the current PHPVariable
158 while (var != null) { // As long as we have PHPVariable
159 parentVar = var.getParent (); // Get the parent PHPVariable
161 if (parentVar != null) { // Is there a parent?
162 if (parentVar.getValue ().equals (val)) { // Get the PHPValue for the parent PHPVariable and check
163 // whether it is the same
164 return true; // Return, if we have recursion
171 return false; // No recursion found
175 * This method updates the 'static' variables list.
176 * It does a replication between the 'static' list (the variable list which
177 * is a member of this DBG interface object) and the DBG variable list
178 * (the list of variables which is received from PHP via DBG with the current suspend)
179 * Replication is done in the following way:
181 * <li> It looks for new variables within the DBG variables list and
182 * adds them to the 'static' list.
183 * <li> It looks for changed variables copies the current value to the variable within
184 * the 'static list' and mark these variables as 'hasChanged' (which uses the UI
185 * for showing the variable with a different color).
186 * <li> It looks for variables within the 'static' list, and removes them
187 * from the 'static' list in case the do not appear within the DBG list.
190 * @param varListOld The 'static' list of variables which are to be updated.
191 * @param varListNew The new list of (current) variables from DBG.
193 private void updateVariableList (Vector varListOld, Vector varListNew)
195 PHPVariable varOld; // The variable from the 'static' list
196 PHPVariable varNew; // The variable from the DBG list
197 PHPValue valOld; // The value of the current variable from 'static' list
198 PHPValue valNew; // The value of the current variable from DBG list
199 int n; // Index for the DBG list
200 int o; // Index for the static list
202 // Add the variables (and childs) to the static list if they are new
203 // and update the values of variables which are already existend within
204 // the 'static' list.
206 for (n = 0; n < varListNew.size (); n++) { // For every variable in 'DBG list'
207 varNew = (PHPVariable) varListNew.get (n); // Get the DBG variable
209 for (o = 0; o < varListOld.size (); o++) { // For every variable in static list
210 varOld = (PHPVariable) varListOld.get (o); // Get the static variable
212 if (varNew.getName ().equals (varOld.getName ())) { // Did we found the variable within the 'static' list?
213 valOld = (PHPValue) varOld.getValue (); // Get the value from 'static'
214 valNew = (PHPValue) varNew.getValue (); // Get the value from DBG
217 if (valOld.hasVariables () || // If the 'static' value has child variables
218 valNew.hasVariables ()) { // or if the DBG value has child variables
219 if (!hasRecursion (varOld) &&
220 !hasRecursion (varNew)) { // Both branches should not have a recursion
221 updateVariableList (valOld.getChildVariables (), // Update the variable list for the child variables
222 valNew.getChildVariables ());
225 else if (!valOld.getValueString ().equals (valNew.getValueString ())) { // Has the value changed?
226 valOld.setValueString (valNew.getValueString ()); // Yes, set the 'static' value (variable) to the new value
227 varOld.setValueChanged (true); // and set the 'has changed' flag, so that the variable view
228 // could show the user the changed status with a different
232 // varOld.setValueChanged (false); // Reset the 'has changed' flag
235 catch (DebugException e) { // That's, because of the hasVariables method
238 break; // Found the variable,
242 if (o == varListOld.size ()) { // Did we found the variable within the static list?
243 varListOld.add (varNew); // No, then add the DBG variable to the static list
247 // Look for the variables we can remove from the 'static' list
249 for (o = 0; o < varListOld.size (); o++) { // For every variable in 'static' list
250 varOld = (PHPVariable) varListOld.get (o); // Get the static variable
252 for (n = 0; n < varListNew.size (); n++) { // For all variables in 'DBG' list
253 varNew = (PHPVariable) varListNew.get (n); // Get the variable from the 'DBG' list
255 if (varNew.getName ().equals (varOld.getName ())) { // Did we found the 'static' list variable within the 'DBG' list?
256 break; // Yes we found the variable, then leave the loop
260 if (n == varListNew.size ()) { // Did not find the 'static' list variable within the 'DBG' list?
261 varListOld.remove (o); // then remove the 'static' list variable from list
262 o -= 1; // Adjust the 'static' list index
270 * This function returns the array of PHPVariables for this stackframe
271 * The PHPVariables should not change (newly build up) between two steps
273 * A PHPVariable with the same name but with different object ID is
274 * handled as a new variable.
276 * TODO Remove the intermediate storage array
278 * @return The array of PHPVariables for this stackframe.
280 public IVariable[] getVariables() throws DebugException {
281 PHPVariable[] variablesNew; // The intermediate storage of the variable array we get from DBG proxy
283 //variablesNew = this.getPHPDBGProxy ().readVariables (this); // Get the variable array from DBG proxy
284 //variables = variablesNew; // Store the array the stackframes member variable
286 if (!isUpToDate ()) {
287 resetHasChangedInfo (varList);
288 updateVariableList (varList, this.getPHPDBGProxy ().readVariables (this));
291 variables = (PHPVariable[]) varList.toArray (new PHPVariable[varList.size ()]);
294 return variables; // Give the array back to user interface
300 private PHPVariable findVariable (Vector varList, String varname) {
301 PHPVariable variable;
305 for (i = 0; i < varList.size (); i++) { // For all variables
306 variable = (PHPVariable) varList.get (i); // Get the variable
307 value = (PHPValue) variable.getValue (); // Get the value of the variable
310 if (value.hasVariables ()) { // Does the variable/value have children
311 if (!hasRecursion (variable)) { // Don't follow recursive variable/values
312 variable = findVariable (value.getChildVariables (), varname);
314 if (variable != null) {
319 else if ((variable.getName ()).equals (varname)) { //
323 catch (DebugException e) { // That's, because of the hasVariables method
331 * This method is called from the UI (e.g. from PHPDebugHover
332 * to find the variable the mouse is pointing to)
334 * @param s The variable name we are looking for.
337 public IVariable findVariable (String s) throws DebugException {
338 if (!isUpToDate ()) {
339 resetHasChangedInfo (varList);
340 updateVariableList (varList, this.getPHPDBGProxy ().readVariables (this));
343 variables = (PHPVariable[]) varList.toArray (new PHPVariable[varList.size ()]);
346 return (findVariable (varList, s)); // Prefix the variable name with $
352 public boolean hasVariables () throws DebugException {
353 return (varList.size () > 0);
356 public int getLineNumber() {
360 public void setLineNumber(int line) {
364 public int getCharStart() throws DebugException {
369 public int getCharEnd() throws DebugException {
374 public String getName() {
375 StringBuffer name = new StringBuffer();
377 if (!this.getDescription().equals ("")) {
378 name.append (this.getDescription ());
381 name.append (this.getFileName ());
384 name.append (" [line ");
385 name.append (this.getLineNumber ());
388 return name.toString();
391 public String getFileName() {
395 public void setDescription(String desc) {
396 this.description= desc;
399 public String getDescription() {
400 return this.description;
403 public IRegisterGroup[] getRegisterGroups() throws DebugException {
407 public boolean hasRegisterGroups() throws DebugException {
411 public String getModelIdentifier() {
412 return this.getThread().getModelIdentifier();
415 public IDebugTarget getDebugTarget() {
416 return this.getThread().getDebugTarget();
419 public ILaunch getLaunch() {
420 return this.getDebugTarget().getLaunch();
423 public boolean canStepInto() {
427 public boolean canStepOver() {
431 public boolean canStepReturn() {
435 public boolean isStepping() {
442 public void stepInto () throws DebugException {
447 thread.prepareForResume (DebugEvent.STEP_INTO); // Don't know why, but this is necessary
448 this.getPHPDBGProxy ().readStepIntoEnd (PHPStackFrame.this);
450 ev = new DebugEvent (this.getThread (), DebugEvent.RESUME, DebugEvent.STEP_INTO);
451 DebugPlugin.getDefault().fireDebugEventSet (new DebugEvent[] { ev });
457 public void stepOver () throws DebugException {
462 thread.prepareForResume (DebugEvent.STEP_OVER);
463 this.getPHPDBGProxy ().readStepOverEnd (PHPStackFrame.this) ;
465 ev = new DebugEvent (this.getThread (), DebugEvent.RESUME, DebugEvent.STEP_OVER);
466 DebugPlugin.getDefault ().fireDebugEventSet (new DebugEvent[] { ev });
472 public void stepReturn () throws DebugException {
477 thread.prepareForResume (DebugEvent.STEP_RETURN);
478 this.getPHPDBGProxy ().readStepReturnEnd (PHPStackFrame.this) ;
480 ev = new DebugEvent (this.getThread (), DebugEvent.RESUME, DebugEvent.STEP_RETURN);
481 DebugPlugin.getDefault ().fireDebugEventSet (new DebugEvent[] { ev });
485 public boolean canResume() {
486 return this.getThread().canResume();
489 public boolean canSuspend() {
490 return this.getThread().canSuspend();
493 public boolean isSuspended() {
494 return this.getThread().isSuspended();
497 public void resume() throws DebugException {
499 this.getThread().resume();
502 public void suspend() throws DebugException {
505 public boolean canTerminate() {
506 return this.getThread().canTerminate();
509 public boolean isTerminated() {
510 return this.getThread().isTerminated();
513 public void terminate() throws DebugException {
514 getPHPDBGProxy().stop();
517 public int getIndex() {
521 public void setIndex (int index) {
525 public PHPDBGProxy getPHPDBGProxy() {
526 PHPDebugTarget DebugTarget;
528 DebugTarget = (PHPDebugTarget) thread.getDebugTarget ();
530 return DebugTarget.getPHPDBGProxy ();
533 public void setFile(String file) {
537 public int getModNo() {
542 * This function is needed when sorting the stackframes by their index numbers.
544 * @param obj The stackframe which this one is compared to.
547 * <li> -1 if the index of this stackframe is less.
548 * <li> 0 if the index of both stackfream is equal (should no happen).
549 * <li> 1 if the index of this stackfram is greater.
552 public int compareTo (Object obj)
554 if (index < ((PHPStackFrame) obj).getIndex ()) {
557 else if (index > ((PHPStackFrame) obj).getIndex ()) {