Package org.erlide.util.erlang

Source Code of org.erlide.util.erlang.OtpErlang

package org.erlide.util.erlang;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import com.ericsson.otp.erlang.OtpErlangAtom;
import com.ericsson.otp.erlang.OtpErlangBinary;
import com.ericsson.otp.erlang.OtpErlangException;
import com.ericsson.otp.erlang.OtpErlangList;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangString;
import com.ericsson.otp.erlang.OtpErlangTuple;
import com.ericsson.otp.erlang.OtpOutputStream;
import com.google.common.collect.Lists;

public class OtpErlang {

    public static OtpErlangList mkList(final OtpErlangObject... args) {
        return new OtpErlangList(args);
    }

    public static OtpErlangList mkList(final Collection<OtpErlangObject> args) {
        return new OtpErlangList(args.toArray(new OtpErlangObject[args.size()]));
    }

    public static OtpErlangTuple mkTuple(final OtpErlangObject... args) {
        return new OtpErlangTuple(args);
    }

    public static OtpErlangList mkStringList(final Collection<?> args) {
        final List<OtpErlangObject> result = Lists.newArrayList();
        for (final Object s : args) {
            result.add(new OtpErlangString(s.toString()));
        }
        return mkList(result);
    }

    // for debugging purposes
    public static long sizeOf(final OtpErlangObject obj) {
        final OtpOutputStream buf = new OtpOutputStream(obj);
        try {
            return buf.size();
        } finally {
            try {
                buf.close();
            } catch (final IOException e) {
            }
        }
    }

    public static TermParser getTermParser() {
        return new TermParser();
    }

    final private static TermParser TERM_PARSER = OtpErlang.getTermParser();

    public static OtpErlangObject parse(final String string) throws TermParserException {
        return TERM_PARSER.parse(string);
    }

    /**
     * Build an Erlang (extended) term from a textual description. For example,
     * <code> format("{hello, ~s, [~a, _]}", "myname", "mykey")
     * </code> gives the equivalent of <code> {hello, "myname", [mykey, _]}
     * </code>.
     * <p>
     * Items beginning with ~ are placeholders that will be replaced with the
     * corresponding argument (from left to right). The text after the ~ is the
     * type signature of the argument, so that automatic conversion Java->Erlang
     * can be done. See TypeConverter.java2erlang for details.
     *
     * @see org.erlide.util.erlang.TypeConverter
     */
    public static OtpErlangObject format(final String fmt, final Object... args)
            throws TermParserException, SignatureException {
        final List<Object> values = new ArrayList<Object>(Arrays.asList(args));
        final OtpErlangObject result = fill(parse(fmt), values);
        return result;
    }

    public static Bindings match(final String pattern, final String term)
            throws TermParserException {
        return match(parse(pattern), parse(term), new BindingsImpl());
    }

    public static Bindings match(final String pattern, final OtpErlangObject term)
            throws TermParserException {
        return match(parse(pattern), term, new BindingsImpl());
    }

    public static Bindings match(final String pattern, final OtpErlangObject term,
            final Bindings bindings) throws TermParserException {
        return match(parse(pattern), term, bindings);
    }

    public static Bindings match(final String pattern, final String term,
            final Bindings bindings) throws TermParserException {
        return match(parse(pattern), parse(term), bindings);
    }

    public static Bindings match(final OtpErlangObject pattern, final OtpErlangObject term) {
        return match(pattern, term, new BindingsImpl());
    }

    public static Bindings match(final OtpErlangObject pattern, final String term)
            throws TermParserException {
        return match(pattern, parse(term), new BindingsImpl());
    }

    /**
     * Match two Erlang terms.
     * <p>
     * Patterns have an extended syntax:
     * <ul>
     * <li>Variables can have a type signature attached, like for example
     * <code>Var:i</code>. Its meaning is that the type of the value must match
     * too.</li>
     * <li>The tail of a list can only be a variable.</li>
     * </ul>
     * <p>
     * The returned value is null if there was any mismatch, otherwise it is a
     * map of variable names to matched values. <br>
     *
     */
    public static Bindings match(final OtpErlangObject pattern,
            final OtpErlangObject term, final Bindings bindings) {
        if (pattern == null && term == null) {
            return bindings;
        }
        if (pattern == null || term == null) {
            return null;
        }
        if (pattern instanceof OtpPatternVariable) {
            final OtpPatternVariable var = (OtpPatternVariable) pattern;
            if (!TypeConverter.doesMatchSignature(term, var.getSignature())) {
                return null;
            }
            if (var.getName().equals("_")) {
                return bindings;
            }
            final Bindings result = new BindingsImpl(bindings);
            final OtpErlangObject old = bindings.get(var.getName());
            if (old == null) {
                // no previous binding
                result.put(var.getName(), term);
                return result;
            }
            return old.equals(term) ? result : null;
        }
        if (!pattern.getClass().equals(term.getClass())) {
            return null;
        }

        if (pattern instanceof OtpErlangList) {
            return matchList(pattern, term, bindings);
        } else if (pattern instanceof OtpErlangTuple) {
            return matchTuple(((OtpErlangTuple) pattern).elements(),
                    ((OtpErlangTuple) term).elements(), bindings);
        } else if (pattern.equals(term)) {
            return bindings;
        }
        return null;
    }

    private static Bindings matchList(final OtpErlangObject pattern,
            final OtpErlangObject term, final Bindings bindings) {
        final OtpErlangList lpattern = (OtpErlangList) pattern;
        final OtpErlangList lterm = (OtpErlangList) term;
        final int patternArity = lpattern.arity();
        final int termArity = lterm.arity();
        if (patternArity > termArity) {
            return null;
        }
        if (patternArity < termArity && lpattern.isProper()) {
            return null;
        }
        if (patternArity == termArity && lpattern.isProper() != lterm.isProper()) {
            return null;
        }
        Bindings rez = bindings;
        for (int i = 0; i < patternArity; i++) {
            rez = match(lpattern.elementAt(i), lterm.elementAt(i), rez);
            if (rez == null) {
                return null;
            }
        }
        if (patternArity == termArity) {
            rez = match(lpattern.getLastTail(), lterm.getLastTail(), rez);
            return rez;
        }
        if (lpattern.getLastTail() instanceof OtpPatternVariable) {
            return match(lpattern.getLastTail(), lterm.getNthTail(patternArity), rez);
        }
        return match(lpattern.getLastTail(), lterm.getLastTail(), rez);
    }

    private static OtpErlangObject fill(final OtpErlangObject template,
            final List<Object> values) throws SignatureException, TermParserException {
        if (values.isEmpty()) {
            return template;
        }
        if (template instanceof OtpErlangList) {
            final OtpErlangObject[] elements = ((OtpErlangList) template).elements();
            final List<OtpErlangObject> result = new ArrayList<OtpErlangObject>(
                    elements.length);
            for (final OtpErlangObject elem : elements) {
                result.add(fill(elem, values));
            }
            return new OtpErlangList(result.toArray(elements));
        } else if (template instanceof OtpErlangTuple) {
            final OtpErlangObject[] elements = ((OtpErlangTuple) template).elements();
            final List<OtpErlangObject> result = new ArrayList<OtpErlangObject>(
                    elements.length);
            for (final OtpErlangObject elem : elements) {
                result.add(fill(elem, values));
            }
            return new OtpErlangTuple(result.toArray(elements));
        } else if (template instanceof OtpFormatPlaceholder) {
            final OtpFormatPlaceholder holder = (OtpFormatPlaceholder) template;
            final Object ret = values.remove(0);
            final Signature[] signs = Signature.parse(holder.getName());
            if (signs.length == 0 && !(ret instanceof OtpErlangObject)) {
                throw new TermParserException("funny placeholder");
            }
            final Signature sign = signs.length == 0 ? new Signature('x') : signs[0];
            return TypeConverter.java2erlang(ret, sign);
        } else {
            return template;
        }
    }

    private static Bindings matchTuple(final OtpErlangObject[] patterns,
            final OtpErlangObject[] terms, final Bindings bindings) {
        if (patterns.length != terms.length) {
            return null;
        }
        Bindings result = new BindingsImpl(bindings);
        for (int i = 0; i < patterns.length; i++) {
            result = match(patterns[i], terms[i], result);
            if (result == null) {
                return null;
            }
        }
        return result;
    }

    /**
     * This is useful if a value can be anything, but we need to see it as a
     * string (but without any quotes if it really is a string).
     *
     * @param target
     * @return
     */
    public static String asString(final OtpErlangObject target) {
        if (target instanceof OtpErlangAtom) {
            return ((OtpErlangAtom) target).atomValue();
        } else if (target instanceof OtpErlangString) {
            return ((OtpErlangString) target).stringValue();
        } else if (target instanceof OtpErlangBinary) {
            return new String(((OtpErlangBinary) target).binaryValue());
        } else if (target instanceof OtpErlangList) {
            try {
                return ((OtpErlangList) target).stringValue();
            } catch (final OtpErlangException e) {
                return target.toString();
            }
        } else {
            return target.toString();
        }
    }

}
TOP

Related Classes of org.erlide.util.erlang.OtpErlang

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.