Package org.epic.debug.db

Source Code of org.epic.debug.db.PerlVariable

package org.epic.debug.db;

import java.util.*;

import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.*;
import org.epic.debug.PerlDebugPlugin;
import org.epic.debug.ui.action.HighlightVarUpdatesActionDelegate;

/**
* Abstract base class for objects that can appear in the Variables
* view of the debugger. Note that this category includes array
* elements and hash keys besides of real Perl variables.
*
* @author jploski
*/
public abstract class PerlVariable extends DebugElement implements IVariable
{
    private final DebuggerInterface db;
    private final StackFrame frame;
    private final DumpedEntity entity;
    private PerlValue value;
    private String quotedName;
    private Boolean contentChanged;
   
    /**
     * @param db        interface to the Perl debugger
     * @param frame     stack frame which contains this variable
     * @param entity    variable's contents received from the debugger
     */
    protected PerlVariable(
        DebuggerInterface db,
        StackFrame frame,
        DumpedEntity entity) throws DebugException
    {
        super(frame.getDebugTarget());
       
        this.db = db;
        this.frame = frame;
        this.entity = entity;
    }
   
    /**
     * @return interface to the Perl debugger which can be used
     *         to obtain further details about the variable (such
     *         as the contained subvariables)
     */
    public DebuggerInterface getDebuggerInterface()
    {
        return db;
    }
   
    /**
     * @return variable's contents received from the debugger
     */
    public DumpedEntity getDumpedEntity()
    {
        return entity;
    }
   
    /**
     * @return a Perl expression which resolves to a reference to
     *         this variable when evaluated in context containing
     *         the enclosing stack frame (as provided by PadWalker)
     *         in hash reference $h
     */
    public abstract String getExpression() throws DebugException;
   
    public String getModelIdentifier()
    {
        return getDebugTarget().getModelIdentifier();
    }

    /**
     * @return variable name; by default it follows the naming
     *         convention described in
     *         {@link org.epic.debug.db.DumpedEntity#getName()};
     *         however, subclasses may override this convention
     */
    public String getName() throws DebugException
    {
        return entity.getName();
    }

    /**
     * @see org.epic.debug.db.DumpedEntity#getReferenceTypeName
     */
    public String getReferenceTypeName() throws DebugException
    {
        return entity.getReferenceType();
    }
   
    /**
     * @return stack frame which contains this variable
     */
    public StackFrame getStackFrame()
    {
        return frame;
    }

    /**
     * @return the hash, array, scalar or other value referred to
     *         by this variable. Note that this reference may be
     *         indirect. That is, the real Perl variable might refer
     *         to another variable and so on, until a value is
     *         eventually reached or a circular reference is formed.
     */
    public IValue getValue() throws DebugException
    {
        // Note: this method, in general, lazily retrieves
        // the variable's value by querying the Perl debugger
       
        if (value != null) return value;
       
        if (isHash())
        {
            value = new HashValue(getDebugTarget(), this);
        }
        else if (isArray())
        {
            if ("@_".equals(getName()))
                value = new ArgsArrayValue(getDebugTarget(), this);
            else
                value = new ArrayValue(getDebugTarget(), this);
        }
        else // if (isScalar()) and "unsupported" types such as CODE, GLOB, ...
        {
            value = new ScalarValue(getDebugTarget(), this);
        }
        return value;
    }
   
    public boolean hasContentChanged() throws DebugException
    {
        if (!HighlightVarUpdatesActionDelegate.getPreferenceValue())
            return false;
       
        if (contentChanged == null) computeContentChanged();
        return contentChanged.booleanValue();
    }

    public boolean hasValueChanged() throws DebugException
    {
        if (!HighlightVarUpdatesActionDelegate.getPreferenceValue())
            return false;
       
        if (getName().startsWith("FileHandle"))
        {
            // TODO: we don't get correct addresses from dumpvar_epic
            // under which to remember the values of GLOBs... so they
            // always appear "fresh" at this point.
            return false;
        }
        PerlVariable prev = (PerlVariable) getStackFrame().getPreviousVariable(this);
        if (prev == null) return true;
       
        String now = getDumpedEntity().getImmediateValue();
        if (now == null) now = "undef";

        String then = prev.getDumpedEntity().getImmediateValue();
        if (then == null) then = "undef";

        return !now.equals(then) || Boolean.TRUE.equals(contentChanged);       
    }

    /**
     * @return true if this variable refers (possibly indirectly)
     *         to a list
     */
    public boolean isArray() throws DebugException
    {
        return "ARRAY".equals(getReferenceTypeName());
    }
   
    /**
     * @return true if this variable refers (possibly indirectly)
     *         to a hash
     */
    public boolean isHash() throws DebugException
    {
        return "HASH".equals(getReferenceTypeName());
    }
   
    /**
     * @return false if it is a package-scope variable;
     *         true otherwise
     */
    public boolean isPackageScope()
    {
        return false;
    }

    /**
     * @return true if this variable refers (possibly indirectly)
     *         to a scalar
     */
    public boolean isScalar() throws DebugException
    {
        return "SCALAR".equals(getReferenceTypeName());
    }

    /**
     * This operation is not supported.
     */
    public void setValue(String expression) throws DebugException
    {
        throwNotSupported();
    }

    /**
     * This operation is not supported.
     */
    public void setValue(IValue value) throws DebugException
    {
      throwNotSupported();
    }

    /**
     * @return false, we do not support value modification through
     *         the usual interface; users may modify variables by
     *         evaluating expressions, but the effects of such
     *         modifications won't be noticed by the front-end
     *         until the next suspend event
     */
    public boolean supportsValueModification()
    {
        return false;
    }

    /**
     * This operation is not supported.
     */
    public boolean verifyValue(String expression) throws DebugException
    {
        throwNotSupported();
        return false;
    }

    /**
     * This operation is not supported.
     */
    public boolean verifyValue(IValue value) throws DebugException
    {
        throwNotSupported();
        return false;
    }
   
    /**
     * @return a Perl expression which yields the name of this variable
     */
    protected String getQuotedName() throws DebugException
    {
        if (quotedName == null) // lazy initialization
        {
            String name = getName();
            boolean clean = true;
            for (int i = 0; i < name.length(); i++)
            {
                char c = name.charAt(i);
                if (c >= 256 || c == '\'') { clean = false; break; }
            }
           
            if (clean) quotedName = "'" + name + "'";
            else // pack those pesky Unicode characters
            {
                StringBuffer buf = new StringBuffer("pack('");
                for (int i = 0; i < name.length(); i++) buf.append('U');
                buf.append("',");
                for (int i = 0; i < name.length(); i++)
                {
                    buf.append((int) name.charAt(i));
                    buf.append(',');
                }
                buf.append(')');
                quotedName = buf.toString();
            }
        }
        return quotedName;
    }
   
    private void computeContentChanged() throws DebugException
    {
        if (!getValue().hasVariables() || getName().equals("%!"))
        {
            // The hash %! seems special in that the addresses of
            // its keys reported by dumpvar_epic are not constant.
            // We ignore it to avoid false contentChanged alerts.
            contentChanged = Boolean.FALSE;
            return;
        }
       
        LinkedList queue = new LinkedList();
        Set visited = new HashSet(); // to avoid infinite recursion
        queue.add(getPerlVariables(getValue()));

        while (!queue.isEmpty())
        {           
            IVariable[] vars = (IVariable[]) queue.removeFirst();
       
            for (int i = 0; i < vars.length; i++)
            {               
                PerlVariable var = (PerlVariable) vars[i];
                if (visited.add(var.getDumpedEntity().getAddress()))
                {
                    if (var.hasValueChanged())
                    {
                        contentChanged = Boolean.TRUE;
                        return;
                    }
                    if (var.getValue().hasVariables())
                        queue.add(getPerlVariables(var.getValue()));
                }
            }
        }
        contentChanged = Boolean.FALSE;
    }
   
    private IVariable[] getPerlVariables(IValue value) throws DebugException
    {
      IVariable[] vars = value.getVariables();
      if (vars.length == 0 || vars[0] instanceof PerlVariable) return vars;
      else
      {
        assert vars[0] instanceof ArraySlice;
        List elements = new ArrayList();
        for (int i = 0; i < vars.length; i++)
          elements.addAll(Arrays.asList(getPerlVariables(vars[i].getValue())));
        return (IVariable[]) elements.toArray(new IVariable[elements.size()]);
      }
    }
   
    private void throwNotSupported() throws DebugException
    {
        throw new DebugException(new Status(
            Status.ERROR,
            PerlDebugPlugin.getUniqueIdentifier(),
            DebugException.NOT_SUPPORTED,
            "Operation not supported",
            null));
    }
}
TOP

Related Classes of org.epic.debug.db.PerlVariable

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.