Package org.erlide.backend.debug.model

Source Code of org.erlide.backend.debug.model.IndexedErlangValue

package org.erlide.backend.debug.model;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
import java.util.Collection;
import java.util.List;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.IIndexedValue;
import org.eclipse.debug.core.model.IVariable;
import org.erlide.engine.ErlangEngine;
import org.erlide.engine.model.ErlModelException;
import org.erlide.engine.model.IErlModel;
import org.erlide.engine.model.erlang.IErlPreprocessorDef;
import org.erlide.engine.model.erlang.IErlRecordDef;
import org.erlide.engine.model.erlang.IErlRecordField;
import org.erlide.engine.model.root.ErlElementKind;
import org.erlide.engine.model.root.IErlElement;
import org.erlide.engine.model.root.IErlProject;

import com.ericsson.otp.erlang.OtpErlangAtom;
import com.ericsson.otp.erlang.OtpErlangBinary;
import com.ericsson.otp.erlang.OtpErlangList;
import com.ericsson.otp.erlang.OtpErlangLong;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangString;
import com.ericsson.otp.erlang.OtpErlangTuple;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;

public class IndexedErlangValue extends ErlangValue implements IIndexedValue {
    private static final List<IErlElement> EMPTY_LIST = Lists.newArrayList();

    // FIXME JC Maybe we should use polymorphism for records?
    protected IErlRecordDef record; // set if this value is a record
    protected OtpErlangList list; // set if this value is a string-coded list

    // TODO not for regular lists too?

    public IndexedErlangValue(final IDebugTarget target, final String varName,
            final OtpErlangObject value, final ErlangProcess process,
            final String moduleName) {
        super(target, varName, value, process, moduleName);
        record = checkRecord(value);
        list = checkList(value);
    }

    private OtpErlangList checkList(final OtpErlangObject theValue) {
        if (theValue instanceof OtpErlangString) {
            final OtpErlangString os = (OtpErlangString) theValue;
            final String s = os.stringValue();
            // TODO real encoding?
            final byte[] b = s.getBytes(Charsets.ISO_8859_1);
            if (!looksLikeAscii(b)) {
                return new OtpErlangList(s);
            }
        }
        return null;
    }

    @Override
    public int getInitialOffset() {
        return 0;
    }

    @Override
    public int getSize() throws DebugException {
        int arity = getArity();
        if (record != null) {
            --arity;
        }
        return arity;
    }

    @Override
    public IVariable getVariable(final int offset) throws DebugException {
        String name;
        if (record != null) {
            try {
                final IErlRecordField recordField = (IErlRecordField) record
                        .getChildren().get(offset);
                name = recordField.getFieldName();
            } catch (final ErlModelException e) {
                name = varName + ":" + offset;
            }
        } else {
            name = varName + ":" + offset;
        }
        return new ErlangVariable(getDebugTarget(), name, true, getElementAt(offset),
                process, moduleName, -1);
    }

    @Override
    public IVariable[] getVariables(final int offset, final int length)
            throws DebugException {
        final IVariable[] result = new IVariable[length];
        for (int i = 0; i < length; ++i) {
            result[i] = getVariable(i + offset);
        }
        return result;
    }

    private IErlRecordDef checkRecord(final OtpErlangObject o) {
        if (o instanceof OtpErlangTuple) {
            final OtpErlangTuple t = (OtpErlangTuple) o;
            final OtpErlangObject h = t.elementAt(0);
            if (h instanceof OtpErlangAtom) {
                final OtpErlangAtom a = (OtpErlangAtom) h;
                final ErlangDebugTarget target = getErlangDebugTarget();
                IErlPreprocessorDef pd;
                try {
                    pd = ErlangEngine
                            .getInstance()
                            .getModelFindService()
                            .findPreprocessorDef(getErlProjects(target.getProjects()),
                                    moduleName, a.atomValue(), ErlElementKind.RECORD_DEF);
                    if (pd instanceof IErlRecordDef) {
                        final IErlRecordDef r = (IErlRecordDef) pd;
                        if (r.hasChildren() && r.getChildCount() + 1 == t.arity()) {
                            return r;
                        }
                    }
                } catch (final CoreException e) {
                }
            }
        }
        return null;
    }

    private Collection<IErlProject> getErlProjects(final Collection<IProject> projects) {
        final List<IErlProject> result = Lists.newArrayListWithCapacity(projects.size());
        final IErlModel model = ErlangEngine.getInstance().getModel();
        for (final IProject project : projects) {
            final IErlElement element = model.getChildWithResource(project);
            if (element instanceof IErlProject) {
                final IErlProject erlProject = (IErlProject) element;
                result.add(erlProject);
            }
        }
        return result;
    }

    @Override
    public String getReferenceTypeName() throws DebugException {
        if (record != null) {
            return "record";
        }
        return super.getReferenceTypeName();
    }

    @Override
    public String getValueString() throws DebugException {
        if (record != null) {
            return getRecordValueString(record, value);
        } else if (list != null) {
            return getListValueString(list);
        } else {
            return getValueString(value, false);
        }
    }

    private String getValueString(final OtpErlangObject o, final boolean recordCheck)
            throws DebugException {
        if (o instanceof OtpErlangBinary) {
            final OtpErlangBinary b = (OtpErlangBinary) o;
            return getBinaryValueString(b);
        } else if (o instanceof OtpErlangTuple) {
            if (recordCheck) {
                final IErlRecordDef r = checkRecord(o);
                if (r != null) {
                    return getRecordValueString(r, o);
                }
            }
            final OtpErlangTuple t = (OtpErlangTuple) o;
            return getTupleValueString(t);
        } else if (o instanceof OtpErlangList) {
            final OtpErlangList l = (OtpErlangList) o;
            return getListValueString(l);
        } else {
            return o.toString();
        }
    }

    private String getRecordValueString(final IErlRecordDef r, final OtpErlangObject o) {
        final StringBuilder b = new StringBuilder();
        List<IErlElement> children;
        try {
            children = r.getChildren();
        } catch (final ErlModelException e) {
            children = EMPTY_LIST;
        }
        final OtpErlangTuple t = (OtpErlangTuple) o;
        b.append(t.elementAt(0)).append("#{");
        final int n = children.size();
        if (n > 0) {
            for (int i = 0; i < n; i++) {
                final IErlRecordField field = (IErlRecordField) children.get(i);
                b.append(field.getFieldName()).append('=')
                        .append(t.elementAt(i + 1).toString()).append(", ");
            }
            b.setLength(b.length() - 2);
        }
        b.append('}');
        return b.toString();
    }

    private String getListValueString(final OtpErlangList l) throws DebugException {
        final StringBuilder b = new StringBuilder("[");
        if (l.arity() > 0) {
            for (final OtpErlangObject o : l) {
                b.append(getValueString(o, true)).append(", ");
            }
            b.setLength(b.length() - 2);
        }
        b.append(']');
        return b.toString();
    }

    private String getTupleValueString(final OtpErlangTuple t) throws DebugException {
        final StringBuilder b = new StringBuilder("{");
        if (t.arity() > 0) {
            for (final OtpErlangObject o : t.elements()) {
                b.append(getValueString(o, true)).append(", ");
            }
            b.setLength(b.length() - 2);
        }
        b.append('}');
        return b.toString();
    }

    private static String getBinaryValueString(final OtpErlangBinary b) {
        final StringBuilder sb = new StringBuilder("<<");
        if (b.size() > 0) {
            final byte[] bytes = b.binaryValue();
            CharBuffer cb = null;
            if (looksLikeAscii(bytes)) {
                final Charset[] css = { Charsets.UTF_8, Charsets.ISO_8859_1 };
                final Charset[] tryCharsets = css;
                for (final Charset cset : tryCharsets) {
                    final CharsetDecoder cd = cset.newDecoder();
                    cd.onMalformedInput(CodingErrorAction.REPORT);
                    cd.onUnmappableCharacter(CodingErrorAction.REPORT);
                    try {
                        cb = cd.decode(ByteBuffer.wrap(bytes));
                        break;
                    } catch (final CharacterCodingException e) {
                    }
                }
            }
            if (cb != null && cb.length() > 0) {
                sb.append('"').append(cb).append('"');
            } else {
                for (int i = 0, n = bytes.length; i < n; ++i) {
                    int j = bytes[i];
                    if (j < 0) {
                        j += 256;
                    }
                    sb.append(j);
                    if (i < n - 1) {
                        sb.append(',');
                    }
                }
            }
        }
        sb.append(">>");
        return sb.toString();
    }

    private static boolean looksLikeAscii(final byte[] bytes) {
        for (final byte b : bytes) {
            if (b < 32) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean hasVariables() throws DebugException {
        return getArity() != -1;
    }

    protected OtpErlangObject getElementAt(final int index) {
        if (value instanceof OtpErlangTuple) {
            final OtpErlangTuple t = (OtpErlangTuple) value;
            final int ofs = record != null ? 1 : 0;
            return t.elementAt(index + ofs);
        } else if (value instanceof OtpErlangList) {
            final OtpErlangList l = (OtpErlangList) value;
            return l.elementAt(index);
        } else if (value instanceof OtpErlangBinary) {
            final OtpErlangBinary bs = (OtpErlangBinary) value;
            int j = bs.binaryValue()[index];
            if (j < 0) {
                j += 256;
            }
            return new OtpErlangLong(j);
        } else if (list != null) {
            return list.elementAt(index);
        }
        return null;
    }

    protected int getArity() {
        if (value instanceof OtpErlangTuple) {
            final OtpErlangTuple t = (OtpErlangTuple) value;
            return t.arity();
        } else if (value instanceof OtpErlangList) {
            final OtpErlangList l = (OtpErlangList) value;
            return l.arity();
        } else if (value instanceof OtpErlangBinary) {
            final OtpErlangBinary bs = (OtpErlangBinary) value;
            return bs.size();
        } else if (list != null) {
            return list.arity();
        } else {
            return -1;
        }
    }

    @Override
    public IVariable[] getVariables() throws DebugException {
        final int arity = getArity();
        if (arity != -1) {
            return getVariables(0, getSize());
        }
        return null;
    }

}
TOP

Related Classes of org.erlide.backend.debug.model.IndexedErlangValue

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.